shhh <- suppressPackageStartupMessages # It's a library, so shhh!

shhh(library( mgcv ))
shhh(library(dplyr))
shhh(library(ggplot2))
shhh(library(lme4))
shhh(library(tidymv))
shhh(library(gamlss))
shhh(library(gsubfn))
shhh(library(lmerTest))
shhh(library(tidyverse))
shhh(library(boot))
shhh(library(rsample))
shhh(library(plotrix))
shhh(library(ggrepel))
shhh(library(mgcv))
shhh(library(brms))
shhh(library(bayesplot))
shhh(library(tidyr))
shhh(library(car))
shhh(library(HDInterval))
shhh(library(gridExtra))
shhh(library(posterior))
shhh(library(readxl))
shhh(library(stringr))
shhh(library(loo))

shhh(library(coda))
shhh(library(cmdstanr))
shhh(library(rstan))
shhh(library(rstantools))

rstan_options(auto_write=TRUE)
options(mc.cores=parallel::detectCores())
rstan_options(auto_write = TRUE)
theme_set(theme_bw())
options(digits=4)
options(scipen=999)
set.seed(444)

Read in ET Data

file_list <- list.files("/Users/cui/Documents/uzh/PhD/Projects/Russian_Agreement/russian_gender/ref/Eyetracking/", pattern = "*.xlsx", full.names = TRUE)
et_raw <- file_list %>%
  lapply(read_excel) %>%
  bind_rows()

# View(et_raw)

Read in MoTR Data


# The path to the data
data_path <- "./data/"
data_names <- list.files(data_path)

# Read in the data from each participant and add to the data frame
motr_df <- data.frame()
for(name in data_names){
  subj <- gsub("reader_", "", gsub("_reading_measures.csv", "", name))
  temp_df <- read.csv(paste0(data_path, "/", name)) %>% mutate(subj_id = subj)
  motr_df <- rbind(motr_df, temp_df)
} 

motr_df <- motr_df %>% mutate(word_len = nchar(word),
                              word_length = scale(word_len)[,1]) %>% 
  group_by(subj_id, item_id) %>%
  arrange(subj_id, item_id) %>%
  mutate(word_len_pre1 = lag(word_length, n = 1),
         word_len_pre2 = lag(word_length, n = 2)) %>%
  ungroup()


View(motr_df)

# Clean the data
clean_df <- motr_df %>%
  # filter(subj_id != 171) %>%   # acc = 0.8
  filter(! list %in% c(98, 99)) %>% # filter practice and filler items
  mutate(skip = ifelse(total_duration==0, 1, 0),
         FPReg = ifelse(gaze_duration==0, NA, FPReg),
         FPFix = ifelse(gaze_duration==0, NA, FPFix)) %>%
  filter(skip == 0) %>%
  
  gather(measure, value, 18:26) %>%
  mutate(tgt_zero = if_else(measure %in% c("first_duration", "gaze_duration", "go_past_time", "right_bounded_rt", "total_duration") & value == 0, F, T)) %>%
  filter(tgt_zero != F) %>%
  dplyr::select(-tgt_zero, -cond_id, -skip, -word_len) %>%
  mutate(item_id = as.factor(item_id),
         subj_id = as.factor(subj_id)) %>%
  spread(measure, value) %>%
  gather(measure, value, c("first_duration", "gaze_duration", "go_past_time", "right_bounded_rt", "total_duration")) %>%
  mutate(outlier = value > (mean(value, na.rm = TRUE) + 3 * sd(value, na.rm = TRUE))) %>%
  filter(outlier == FALSE) %>%
  dplyr::select(-outlier) %>%
  spread(measure, value) %>%
  gather(measure, value, 21:29) %>%

  mutate(cond = case_when(
    target_gender == "M" & gender_match == "Mis" & type == "stim_adj" ~ "a",
    target_gender == "M" & gender_match == "Mis" & type == "stim_verb" ~ "b",
     target_gender == "M" & gender_match == "Mis" & type == "stim_pred_adj" ~ "c",
    target_gender == "M" & gender_match == "Match" & type == "stim_adj" ~ "d",
    target_gender == "M" & gender_match == "Match" & type == "stim_verb" ~ "e",
    target_gender == "M" & gender_match == "Match" & type == "stim_pred_adj" ~ "f",
    target_gender == "F" & gender_match == "Mis" & type == "stim_adj" ~ "g",
    target_gender == "F" & gender_match == "Mis" & type == "stim_verb" ~ "h",
    target_gender == "F" & gender_match == "Mis" & type == "stim_pred_adj" ~ "i",
    target_gender == "F" & gender_match == "Match" & type == "stim_adj" ~ "j",
    target_gender == "F" & gender_match == "Match" & type == "stim_verb" ~ "k",
    target_gender == "F" & gender_match == "Match" & type == "stim_pred_adj" ~ "l",
    TRUE ~ NA_character_ # This is the default case if none of the above conditions are met
  )) %>%
  dplyr::select(-list, -part, -type_id, -orig_item_number, -case, -animacy, -response_true, -response_chosen, -correctness) #%>%
  # drop_na()

clean_df <- clean_df %>%
  mutate(word = str_replace_all(word, "\\.", "")) %>%
  rowwise() %>%
  mutate(log_freq = ifelse(word %in% et_raw$IA_LABEL, 
                           et_raw$lg_frequency[match(word, et_raw$IA_LABEL)], 
                           NA_real_)) %>%
  ungroup()

View(clean_df)
correctness <- motr_df %>% dplyr::select(item_id, cond_id, subj_id, correctness) %>%
  filter(correctness != 99) %>% 
  distinct()

correctness_summary <- correctness %>%
  group_by(subj_id) %>%
  summarise(mean_correctness = mean(correctness),
            sd_correctness = sd(correctness),
            count = n())

View(correctness_summary)   # only subj_id 171 get acc = 0.8; others all > 0.88

# write.csv(correctness_summary, "./stats/correctness_summary.csv", row.names = FALSE)

RESEARCH QUESTIONS:

  1. Are RTs different in gender-match versus gender-mismatch sentences? ==> main effect of grammaticality (gender match or not)

  2. Are RTs different in Masculine versus Feminine sentence conditions? ==> main effect of gender of target word

  3. Are RTs affected by sentence type (whether different lexical categories of the agreeing element will make the processing more difficult or not)? –> ADJ(adj + pre_adj) v.s. VERB ==> main effect of lexical type of sentences.

  4. Are RTs affected by sentence type (whether agreeing element instantiates internal v.s. external agreement will make a difference in processing difficulty)? –> internal (modifying adjective) v.s. external (verb or predicative adjective) ==> main effect of syntax type of sentences.

  5. Does the grammaticality effect within each lexical sentence type differ from each other? –> Whether the effect of grammaticality depends on the lexical type of the sentence (ADJ? VERB?) ==> interaction between grammaticality and lexical sentence type

6.Does the grammaticality effect within each syntax sentence type differ from each other? –> Whether the effect of grammaticality depends on the syntax type of the sentence (internal? external?) ==> interaction between grammaticality and syntax sentence type

  1. Does the (possible) difference in the sensitivity to the grammaticality manipulation of Masculine versus Feminine conditions differ between lexical sentence types (ADJ v.s. VERB)? ==> 3-way interaction between grammaticality, gender and lexical sentence type

  2. Does the (possible) difference in the sensitivity to the grammaticality manipulation of Masculine versus Feminine conditions differ between syntax sentence types (internal v.s. external)? ==> 3-way interaction between grammaticality, gender and syntax sentence type

contrast coding

# check conditions
clean_df$cond <- factor(clean_df$cond)
summary(clean_df$cond)
   a    b    c    d    e    f    g    h    i    j    k    l 
5922 6255 5805 6309 6498 6156 6129 6309 7623 5562 5616 6912 
clean_df <- clean_df %>% 
  mutate(
    #--------------------- main effects ---------------------
    Gram = ifelse(cond %in% c('a', 'b', 'c', 'g', 'h', 'i'), 1/6, -1/6), # Main effect grammaticality 
    Gen = ifelse(cond %in% c('a','b','c','d','e', 'f'), 1/6, -1/6), # Main effect gender
    TypL = ifelse(cond %in% c('a','c','d','f', 'g', 'i', 'j', 'l'), 1/8, -1/4), # Main effect of sentence type (ap vs v)
    TypS = ifelse(cond %in% c('a', 'd', 'g', 'j'), 1/4, -1/8), # Main effect of sentence type (a vs pv)
    
    #--------------------- 2 way interection ---------------------
    # Gram_x_TypL = ifelse(cond %in% c('a', 'c', 'i'), 1/8,
    #                  ifelse(cond %in% c('d', 'f', 'l'), -1/8,
    #                    ifelse(cond %in% c('e', 'k'), 1/4, -1/4))), # Grammaticality x type (ap v)
    
    # Gram_x_TypS = ifelse(cond %in% c('e', 'f', 'k', 'l'), 1/8,
    #                   ifelse(cond %in% c('b', 'c', 'h', 'i'), -1/8,
    #                          ifelse(cond %in% c('a', 'g'), 1/4, -1/4))), # Grammaticality x type (ap v)
    
    Gram_x_TypL = ifelse(cond %in% c('a', 'c', 'g', 'i', 'e', 'k'), 1/2, -1/2), # Grammaticality x type (ap v)
    Gram_x_TypS = ifelse(cond %in% c('a', 'g', 'e', 'f', 'k', 'l'), 1/2, -1/2), # Grammaticality x type (a pv)

    Gram_TypL_M = ifelse(cond %in% c('a', 'c', 'e'), 1/2, 
                    ifelse(cond %in% c('b', 'd', 'f'), -1/2, 0)), # gram x typl(ap v)_M
    Gram_TypS_M = ifelse(cond %in% c('a', 'e', 'f'), 1/2, 
                ifelse(cond %in% c('b', 'c', 'd'), -1/2, 0)), # gram x typs(a pv)_M
    Gram_TypL_F = ifelse(cond %in% c('g', 'i', 'k'), 1/2, 
                ifelse(cond %in% c('h', 'j', 'l'), -1/2, 0)), # gram x typl(ap v)_F
    Gram_TypS_F = ifelse(cond %in% c('a', 'e', 'f'), 1/2, 
                ifelse(cond %in% c('b', 'c', 'd'), -1/2, 0)), # gram x typs(a pv)_F
    
    #--------------------- 3 way interection ---------------------
    Gram_x_Gen_x_TypL = ifelse(cond %in% c('a', 'c', 'e', 'h', 'j', 'l'), 1/2, -1/2), # gen x typ1(ap v) x gram
    Gram_x_Gen_x_TypS = ifelse(cond %in% c('a', 'e', 'f', 'h', 'i', 'j'), 1/2, -1/2), # gen x typ1(ap v) x gram
    
    #--------------------- Within grammaticality type effects ---------------------
    Typ_Mis = ifelse(cond %in% c('a', 'c', 'g', 'i'), 1/4,
              ifelse(cond %in% c('b', 'h'), -1/2, 0)),  # type_Mis
    Typ_Match = ifelse(cond %in% c('d', 'f', 'j', 'l'), 1/4,
                  ifelse(cond %in% c('e', 'k'), -1/2, 0))  # type_Match
  ) %>% spread(measure, value) %>%
  # filter(word_nr == 3)
  filter(AOI_id == "R3")
  
clean_df
clean_df$target_gender <- factor(clean_df$target_gender)    # F, M
clean_df$gender_match <- factor(clean_df$gender_match)      # Match, Mismatch
clean_df$type <- factor(clean_df$type)                      # adj, pre_adj, verb

X_C_bar1 <- contr.sum(2)
X_C_bar2 <- contr.sum(3)

contrasts(clean_df$target_gender)<- X_C_bar1
contrasts(clean_df$gender_match)<- X_C_bar1
contrasts(clean_df$type)<- X_C_bar2

## Check contrasts
# contrasts(clean_df$target_gender)
# contrasts(clean_df$gender_match)
# contrasts(clean_df$type)    # The contrast is for: h0 -> grand mean; h1 -> adj-grand mean; h2 -> pre-gran mean
fuchs_stats_df = data.frame()
measure_types = c("gaze_duration", "go_past_time", "total_duration", 
                  "FPReg", "RegIn_incl")

for (meas in measure_types){
  print(paste("Fitting model for:", meas))
  
  if (meas %in% c("gaze_duration", "go_past_time", "total_duration")){
      model <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        # mutate(log_meas = log(.data[[meas]])) %>%
        lmer(as.formula(paste("log(", meas, ") ~ gender_match * type + target_gender + word_length + word_len_pre1 + word_len_pre2 + log_freq + 
            (1 + gender_match | subj_id) + (1 | item_id)")), 
            data = ., REML = F)
      coefs <- summary(model)$coefficients
      temp_results <- data.frame(
        measure = meas,
        beta = c("b_0", "b_Gram", "b_adj", "b_pred_adj", "b_fem", "b_len", "b_len_pre1", "b_len_pre2", "b_freq", "b_Gram_x_adj", "b_Gram_x_pred_adj"),
        bval = coefs[, "Estimate"],
        pval = coefs[, "Pr(>|t|)"]
      )
  }else{
      model <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        glmer(as.formula(paste(meas, "~ gender_match * type +  (1 | subj_id)")), 
            data = ., family=binomial(link = "logit"))
      coefs <- summary(model)$coefficients
      temp_results <- data.frame(
        measure = meas,
        beta = c("b_0", "b_Gram", "b_adj", "b_pred_adj", "b_Gram_x_adj", "b_Gram_x_pred_adj"),
        bval = coefs[, "Estimate"],
        pval = coefs[, "Pr(>|z|)"]
        )
  }
    fuchs_stats_df = rbind(fuchs_stats_df, temp_results)
}

fuchs_stats_df = fuchs_stats_df %>%
  mutate(sig = if_else(pval < 0.05, "SIG", ifelse(pval < .1, ".", "")))

# View(fuchs_stats_df)
# write.csv(fuchs_stats_df, "./stats/fuchs_replicates.csv", row.names = FALSE)
stats_df = data.frame()
measure_types = c("first_duration", "gaze_duration", "go_past_time", "total_duration", 
                  "FPReg", "RegIn_incl"
                  )

for (meas in measure_types){
  print(paste("Fitting model for:", meas))
  
  if (meas %in% c("first_duration", "gaze_duration", "go_past_time", "total_duration")){
      model <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        lmer(as.formula(paste("log(", meas, ") ~ Gram + Gen + TypL + TypS + Gram_x_TypL + Gram_x_TypS + Gram_x_Gen_x_TypL + Gram_x_Gen_x_TypS + 
            (1 | item_id) + (1 + Gram | subj_id)")), 
            data = ., REML = F)
      coefs <- summary(model)$coefficients
      temp_results <- data.frame(
        measure = meas,
        beta = c("b_0", "b_Gram", "b_Gen", "b_TypL", "b_TypS", 
                 "b_Gram_x_TypL", "b_Gram_x_TypS", "b_Gram_x_Gen_x_TypL", "b_Gram_x_Gen_x_TypS"),
        bval = coefs[, "Estimate"],
        pval = coefs[, "Pr(>|t|)"]
      )
  }else{
      model <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        glmer(as.formula(paste(meas, "~ Gram + Gram_x_TypL + Gram_x_TypS + Gram_x_Gen_x_TypL + Gram_x_Gen_x_TypS + 
            (1 | item_id) + (1 | subj_id)")), 
            data = ., family=binomial(link = "logit"))
      coefs <- summary(model)$coefficients
      temp_results <- data.frame(
        measure = meas,
        beta = c("b_0", "b_Gram", 
                 "b_Gram_x_TypL", "b_Gram_x_TypS", "b_Gram_x_Gen_x_TypL", "b_Gram_x_Gen_x_TypS"),
        bval = coefs[, "Estimate"],
        pval = coefs[, "Pr(>|z|)"]
        )
  }
    stats_df = rbind(stats_df, temp_results)
}

stats_df = stats_df %>%
  mutate(sig = if_else(pval < 0.05, "SIG", ifelse(pval < .1, ".", "")))

View(stats_df)

# write.csv(stats_df, "./stats/stats_lmer_new.csv", row.names = FALSE)

Model comparison

model_comparison_df = data.frame()
measure_types = c("gaze_duration", "go_past_time", "total_duration", 
                  "FPReg", "RegIn_incl")

for (meas in measure_types){
  print(paste("Compare models for:", meas))
    if (meas %in% c("gaze_duration", "go_past_time", "total_duration")){
        model_l <- clean_df %>% filter(!is.na(.data[[meas]])) %>%
        lmer(as.formula(paste("log(", meas, ") ~  Gram + Gen + TypL  + Gram_x_TypL + Gram_x_Gen_x_TypL + 
            (1 | item_id) + (1 + Gram | subj_id)")), data = ., REML = F)

        model_s <- clean_df %>% filter(!is.na(.data[["go_past_time"]]))  %>% 
        lmer(as.formula(paste("log(", meas, ") ~ Gram + Gen + TypS  + Gram_x_TypS + Gram_x_Gen_x_TypS + 
            (1 | item_id) + (1 + Gram | subj_id)")), data = ., REML = F)
    }else{
        model_l <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        glmer(as.formula(paste(meas, "~ Gram + Gram_x_TypL + Gram_x_Gen_x_TypL +
            (1 | item_id)")), 
            data = ., family=binomial(link = "logit"))
        model_s <- clean_df %>% filter(!is.na(.data[[meas]]))  %>% 
        glmer(as.formula(paste(meas, "~ Gram + Gram_x_TypS + Gram_x_Gen_x_TypS +
            (1 | item_id)")), 
            data = ., family=binomial(link = "logit"))
    }
  
    aic_bic_comparison <- data.frame(
      `Dependent Variable` = meas,
      `Model Type` = c("L model", "S model"),
      AIC = c(AIC(model_l), AIC(model_s)),
      BIC = c(BIC(model_l), BIC(model_s)))
    model_comparison_df = rbind(model_comparison_df, aic_bic_comparison)
}
# write.csv(model_comparison_df, "./stats/model_comparison_lmer.csv", row.names = FALSE)

Fit Bayesian models

function for creating stan data format

createStanDat<-function(d, dv,form){
  
  subj <- as.integer(factor(d$subj_id))
  N_subj <- length(unique(subj))
  item <- as.integer(factor(d$item_id))
  N_items <- length(unique(item))
  X <- unname(model.matrix(form, d))  
  attr(X, which="assign") <- NULL
  
  stanDat <- list(N = nrow(X),           
                  P = ncol(X),              
                  n_u = ncol(X),             
                  n_w = ncol(X),            
                  X = X,                     
                  Z_u = X,                 
                  Z_w = X,                   
                  J = N_subj,                
                  K = N_items,
                  dv = dv,                    
                  subj = subj,
                  item = item)
  stanDat
}
stan_gd <- createStanDat(d=subset(clean_df, !is.na(clean_df$gaze_duration)),
                             form=as.formula("~1+Gram+Gen+TypL+TypS+Gram_x_TypL+Gram_x_TypS+Gram_x_Gen_x_TypL+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_df, !is.na(clean_df$gaze_duration))$gaze_duration)

m1_gd <- stan(file = "stan/maxModel1.stan", 
                data = stan_gd,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
saveRDS(m1_gd, file = "model/m1_gd2.rds")
stan_gpt <- createStanDat(d=subset(clean_df, !is.na(clean_df$go_past_time)),
                             form=as.formula("~1+Gram+Gen+TypL+TypS+Gram_x_TypL+Gram_x_TypS+Gram_x_Gen_x_TypL+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_df, !is.na(clean_df$go_past_time))$go_past_time)

# sample from posterior distribution.
m1_gpt <- stan(file = "stan/maxModel1.stan", 
                data = stan_gpt,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
saveRDS(m1_gpt, file = "model/m1_gpt2.rds")
stan_td <- createStanDat(d=subset(clean_df, !is.na(clean_df$total_duration)),
                             form=as.formula("~1+Gram+Gen+TypL+TypS+Gram_x_TypL+Gram_x_TypS+Gram_x_Gen_x_TypL+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_df, !is.na(clean_df$total_duration))$total_duration)

# sample from posterior distribution.
m1_td <- stan(file = "stan/maxModel1.stan", 
                data = stan_td,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
saveRDS(m1_td, file = "model/m1_td2.rds")

binary dv

stan_fpreg <- createStanDat(d=subset(clean_df, !is.na(clean_df$FPReg)),
                             form=as.formula("~1+Gram+Gen+TypL+TypS+Gram_x_TypL+Gram_x_TypS+Gram_x_Gen_x_TypL+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_df, !is.na(clean_df$FPReg))$FPReg)

# sample from posterior distribution.
m1_fpreg <- stan(file = "stan/logitModel1.stan", 
                data = stan_fpreg,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
saveRDS(m1_fpreg, file = "model/m1_fpreg2.rds")
stan_regin <- createStanDat(d=subset(clean_df, !is.na(clean_df$RegIn_incl)),
                             form=as.formula("~1+Gram+Gen+TypL+TypS+Gram_x_TypL+Gram_x_TypS+Gram_x_Gen_x_TypL+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_df, !is.na(clean_df$RegIn_incl))$RegIn_incl)

# sample from posterior distribution.
m1_regin <- stan(file = "stan/logitModel1.stan", 
                data = stan_regin,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
saveRDS(m1_regin, file = "model/m1_regin2.rds")

Examine fitted stan models

# change m1_gd.rds to other models to check them

m1_gd <- readRDS("model/m1_fpreg.rds")

# check params
summary(m1_gd, pars = c('beta[1]', 'beta[2]', 'beta[3]', 'beta[4]', 'beta[5]', 'beta[6]', 'beta[7]', 'beta[8]', 'beta[9]'))

# check convergence
traceplot(m1_gd, pars = c("beta"))

# check predicts --> posterior parameter distr.
y_posterior <- extract(m1_gd) 
y_posterior$beta[,1] #intercept
y_posterior$beta[,2] #Gram
y_posterior$beta[,3] #Gen
y_posterior$beta[,4] #TypL
y_posterior$beta[,5] #TypS
y_posterior$beta[,6] #Gram_x_TypL
y_posterior$beta[,7] #Gram_x_TypS

# check predicts --> posterior parameter distr. back in normal space
pst_gram <- y_posterior$Gram
pst_gram
density_gram <- density(pst_gram)
plot(density_plot, main = "Density Plot of pst_gram", xlab = "pst_gram values", ylab = "Density", col = "red")

pst_gen <- y_posterior$Gen
pst_gen
density_gen <- density(pst_gen)
plot(density_gen, main = "Density Plot of pst_gen", xlab = "pst_gen values", ylab = "Density", col = "red")

pst_typl <- y_posterior$TypL
pst_typl
density_typl <- density(pst_typl)
plot(density_typl, main = "Density Plot of pst_typl", xlab = "pst_typl values", ylab = "Density", col = "red")

pst_typs <- y_posterior$TypS
pst_typs
density_typs <- density(pst_typs)
plot(density_typs, main = "Density Plot of pst_typs", xlab = "pst_typs values", ylab = "Density", col = "red")

pst_gramxtypl <- y_posterior$Gram_x_TypL
pst_gramxtypl
density_gramxtypl <- density(pst_gramxtypl)
plot(density_gramxtypl, main = "Density Plot of pst_gramxtypl", xlab = "pst_gramxtypl values", ylab = "Density", col = "red")

pst_gramxtyps <- y_posterior$Gram_x_TypS
pst_gramxtyps
density_gramxtyps <- density(pst_gramxtyps)
plot(density_gramxtyps, main = "Density Plot of pst_gramxtyps", xlab = "pst_gramxtyps values", ylab = "Density", col = "red")

pst_gramxgenxtypl <- y_posterior$Gram_x_Gen_x_TypL
pst_gramxgenxtypl
density_gramxgenxtypl <- density(pst_gramxgenxtypl)
plot(density_gramxgenxtypl, main = "Density Plot of pst_gramxgenxtypl", xlab = "pst_gramxgenxtypl values", ylab = "Density", col = "red")


pst_gramxgenxtyps <- y_posterior$Gram_x_Gen_x_TypS
pst_gramxgenxtyps
density_gramxgenxtyps <- density(pst_gramxgenxtyps)
plot(density_gramxgenxtyps, main = "Density Plot of pst_gramxgenxtyps", xlab = "pst_gramxgenxtyps values", ylab = "Density", col = "red")


# check posterior predicts --> the fits looks very good --> suspision of overfit? --> cv validation?
predicts <- y_posterior$Predict_rt
dim(predicts) # 8000 x 1271
y_true <- subset(clean_df, !is.na(clean_df$FPReg))$FPReg
ppc_dens_overlay(y_true, yrep = predicts[1:200, ])
calc_hpdi <- function(samples, prob = 0.95) {
  if(length(samples) < 2) {  # Check if there are too few samples to calculate an interval
    return(c(lower = NA, upper = NA))
  }
  # Ensure samples can be converted to an mcmc object
  tryCatch({
    hpd_interval <- HPDinterval(as.mcmc(samples), prob = prob)
    return(c(lower = hpd_interval[1], upper = hpd_interval[2]))
  }, error = function(e) {
    return(c(lower = NA, upper = NA))  # Return NA if any error occurs
  })
}

compile model results

stats_df <- data.frame()

# Define the measure types corresponding to your models
measure_types <- c("gaze_duration", "go_past_time", "total_duration", "FPReg", "RegIn_incl")

# Loop over each measure type to read the corresponding model and extract data
for (meas in measure_types) {
  if (meas == "gaze_duration") {
      m1 <- readRDS("model/m1_gd2.rds")
    } else if (meas == "go_past_time") {
      m1 <- readRDS("model/m1_gpt2.rds")
    } else if (meas == "total_duration") {
      m1 <- readRDS("model/m1_td2.rds")
    } else if (meas == "FPReg") {
      m1 <- readRDS("model/m1_fpreg2.rds")
    } else if (meas == "RegIn_incl") {
      m1 <- readRDS("model/m1_regin2.rds")
    }

  # Extract posterior distributions
  y_posterior <- extract(m1)
  intercept <- exp(y_posterior$beta[,1])

  betas <- c("b_0", "b_Gram", "b_Gen", "b_TypL", "b_TypS", "b_Gram_x_TypL", "b_Gram_x_TypS", "b_Gram_x_Gen_x_TypL", "b_Gram_x_Gen_x_TypS")
  posterior_samples <- list(intercept, y_posterior$Gram, y_posterior$Gen, y_posterior$TypL, y_posterior$TypS, y_posterior$Gram_x_TypL, y_posterior$Gram_x_TypS, y_posterior$Gram_x_Gen_x_TypL, y_posterior$Gram_x_Gen_x_TypS)
  
  hpdi_95 <- lapply(posterior_samples, function(x) hdi(x, credMass = 0.95))
  hpdi_89 <- lapply(posterior_samples, function(x) hdi(x, credMass = 0.89))

  # Prepare the results data frame
  temp_results <- data.frame(
    measure = rep(meas, length(betas)),
    beta = betas,
    bval_mean = sapply(posterior_samples, mean),
    crI_95_lower = sapply(posterior_samples, function(x) quantile(x, 0.025)),
    crI_95_upper = sapply(posterior_samples, function(x) quantile(x, 0.975)),
    crl_89_lower = sapply(posterior_samples, function(x) quantile(x, 0.055)),
    crl_89_upper = sapply(posterior_samples, function(x) quantile(x, 0.945)),
    hpdi_95_lower = sapply(hpdi_95, function(x) x[1]),
    hpdi_95_upper = sapply(hpdi_95, function(x) x[2]),
    hpdi_89_lower = sapply(hpdi_89, function(x) x[1]),
    hpdi_89_upper = sapply(hpdi_89, function(x) x[2]),
    bval_median = sapply(posterior_samples, median)
  )

  # Append the temp_results to the stats_df data frame
  stats_df <- rbind(stats_df, temp_results)
}

write.csv(stats_df, "./stats/stats_bayesian_new.csv", row.names = FALSE)

OBSERVATIONS:

gpt, gd, td, reg:

  1. Effects of Grammaticality are always significant. –> There are main effect of grammaticality (gender match or not).

  2. Effects of condTypS are significant or nearly significant. –> Very likely, there are main effect of syntactic agreement type (adj vs verb & pred_adj)

  3. The significance of condTypL is always smaller than condTypS. In Bayesian, the crI of beta for TypL (diff between adj vs verb) is always larger and 0 is more to the middle of its distribution.

  • If do sum contrast for each level of type, pred_adj type is significantly different from the grand mean.
  1. For gd, the interaction between TypS and Gram is significant. For td and gpt, it is also near to significance (or 0 to be in the narrow tail of its distr. in Bayesian). –> external or internal agreement will affect the process of mismatches in sentence.

  2. Interaction between TypL and Gram is far from significance.

  3. In td, there are three way interaction between TypL & Gram & Gen. –> coincidence?

CONCLUSION:

  1. Longer rt and more regressions in error setences.
  2. Longer rt and possibly more regressions in external agreement than internal ones. –> external is more difficult.
  3. But rt difference between mismatch and match is bigger in internal than in external. –> internal agreement kind of amplify the processing difficulty in mismatches. Maybe because external sentences are already difficult, so when combined with errors, the rt is not that different from in correct sentence. Maybe because people have their upboundary for the times they spend on difficult sentences? –> obviously, rt(difficult_external_type + error_sentence) < rt(difficult_external_type_sentence) + rt(error_sentence)

Bayesian model comparison

# Exclude outlier points 
clean_data_lexical <- clean_df %>% filter(subj_id != 131)
clean_data_syntax <- clean_df %>% filter(subj_id != 131)

# Refit the models on the cleaned data
lexical_gpt_clean <- createStanDat(d=subset(clean_data_lexical, !is.na(clean_data_lexical$go_past_time)),
                             form=as.formula("~1+Gram+Gen+TypL+Gram_x_TypL+Gram_x_Gen_x_TypL"), 
                             dv=subset(clean_data_lexical, !is.na(clean_data_lexical$go_past_time))$go_past_time)

# lexical_gpt
# sample from posterior distribution.
lexical_gpt_clean <- stan(file = "stan/Modelcomparison.stan", 
                data = lexical_gpt_clean,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99)
                )
# saveRDS(lexical_gpt_clean, file = "model/model_comparison/lexical_gpt_clean.rds")

syntax_gpt_clean <- createStanDat(d=subset(clean_data_syntax, !is.na(clean_data_syntax$go_past_time)),
                             form=as.formula("~1+Gram+Gen+TypS+Gram_x_TypS+Gram_x_Gen_x_TypS"), 
                             dv=subset(clean_data_syntax, !is.na(clean_data_syntax$go_past_time))$go_past_time)

# lexical_gpt
# sample from posterior distribution.
syntax_gpt_clean <- stan(file = "stan/Modelcomparison.stan", 
                data = syntax_gpt_clean,
                iter = 4000, 
                chains = 4,
                control = list(adapt_delta=0.99))
# saveRDS(syntax_gpt_clean, file = "model/model_comparison/syntax_gpt_clean.rds")

# Perform LOO on cleaned models
loo_lexical_clean <- loo(lexical_gpt_clean)
loo_syntax_clean <- loo(syntax_gpt_clean)

# Compare the cleaned models
loo_compare(loo_lexical_clean, loo_syntax_clean)

PLOT

agg_all = df %>%
  group_by(type, gender_match, region, measure) %>%
    summarise(
      m = mean(value),
      s = std.error(value),
      lower = m - 1.96 * s,
      upper = m + 1.96 * s
    ) %>%
  ungroup()
`summarise()` has grouped output by 'type', 'gender_match', 'region'. You can override using the `.groups` argument.
agg_all
fuchs_stats_df <-  read.csv("./stats/fuchs_replicates.csv")
Warning: cannot open file './stats/fuchs_replicates.csv': No such file or directoryError in file(file, "rt") : cannot open the connection

# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_all %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("gaze_duration", "go_past_time", "total_duration")) %>%
  
  mutate(type = factor(type, levels = c("stim_adj", "stim_pred_adj", "stim_verb"), labels=c("Modifying Adj.", "Predicative Adj.",  "Verb"))) %>%
  mutate(measure = factor(measure, levels = c("gaze_duration", "go_past_time", "total_duration"), labels=c("Gaze Duration", "Go Past Times", "Total Duration"))) %>%
  
  ggplot(aes(x=region, y=m, color = gender_match)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=lower-100, ymax=upper+100), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_grid(measure~type, scales = "free_y") +
    # scale_x_continuous(breaks = 1:4, labels = c("critical -2", "critical -1", "critical", "critical +1")) +
    #ggtitle(paste0("Region by region plot for ", stim)) +
    ylab("Reading time (ms)") +
    xlab("Sentence Region") +
  scale_color_manual(values = c("Match" = "#56BCC2", "Mis" = "#E77D72")) +
  #coord_cartesian(ylim=c(0, 900)) +
  theme(
    # axis.text.x = element_text(size = 9),
    legend.position = "bottom"
  )

ggsave(paste0("./images/RT_results_all_types.pdf"), device="pdf", height=5, width=5)

# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_s %>%
  filter(measure %in% c("FPReg", "RegIn_incl")) %>%
  
  mutate(type_s = factor(type_s, levels = c("Modifying_Adj", "Predictive_Adj_Verb"), labels=c("Modifying Adj.", "Predicative Adj. & Verb"))) %>%
    mutate(measure = factor(measure, levels = c("FPReg", "RegIn_incl"), labels=c("Regr. out Prob.", "Regr. in Prob."))) %>%

  ggplot(aes(x=region, y=m, color = gender_match)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=lower-0.2, ymax=upper+0.2), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_grid(measure~type_s, scales = "free_y") +
    ylab("Regression Prob.") +
    xlab("Sentence Region") +
  scale_color_manual(values = c("Match" = "#56BCC2", "Mis" = "#E77D72")) +
  #coord_cartesian(ylim=c(0, 900)) +
  theme(
    # axis.text.x = element_text(size = 9),
    legend.position = "bottom"
  )
ggsave(paste0("./images/Regression_results_synt_position2.pdf"), device="pdf", height=3.4, width=5)

agg_s2 = df %>%
  group_by(type_s, subj_id, region, measure) %>%
    summarise(
      m = mean(value),
    ) %>%
  ungroup() %>%
  group_by(type_s, region, measure) %>%
  pivot_wider(
    names_from = type_s,
    values_from = m,
    names_prefix = "mean_"
  ) %>%
  # Calculate the difference between 'Mis' and 'Match'
  drop_na() %>%
  mutate(
    diff = mean_Predictive_Adj_Verb - mean_Modifying_Adj
  ) %>%
  group_by(region, measure) %>%
  summarise(
    m_diff = mean(diff),
    s = std.error(diff),
    lower = m_diff - 1.96 * s,
    upper = m_diff + 1.96 * s
  ) %>%
  ungroup()
`summarise()` has grouped output by 'type_s', 'subj_id', 'region'. You can override using the `.groups` argument.`summarise()` has grouped output by 'region'. You can override using the `.groups` argument.

agg_s3 = df %>%
  group_by(type_s, gender_match, item_id, region, measure) %>%
    summarise(
      m = mean(value)
    ) %>%
  ungroup() %>%
  group_by(type_s, region, measure) %>%
  pivot_wider(
    names_from = gender_match,
    values_from = m,
    names_prefix = "mean_"
  ) %>%
  # Calculate the difference between 'Mis' and 'Match'
  drop_na() %>%
  mutate(
    diff = mean_Mis - mean_Match
  ) %>%
  group_by(type_s, region, measure) %>%
  summarise(
    m_diff = mean(diff),
    s = std.error(diff),
    lower = m_diff - 1.96 * s,
    upper = m_diff + 1.96 * s
  ) %>%
  ungroup()
`summarise()` has grouped output by 'type_s', 'gender_match', 'item_id', 'region'. You can override using the `.groups` argument.`summarise()` has grouped output by 'type_s', 'region'. You can override using the `.groups` argument.

agg_s3 %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("FPReg", "RegIn_incl")) %>%
  
  mutate(type_s = factor(type_s, levels = c("Modifying_Adj", "Predictive_Adj_Verb"), labels=c("Modifying Adj.", "Predicative Adj. & Verb"))) %>%
  mutate(measure = factor(measure, levels = c("FPReg", "RegIn_incl"), labels=c("First Pass Regression out Prob.", "Regression in Prob."))) %>%

  ggplot(aes(x=region, y=m_diff, color = type_s)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=-0.3, ymax=0.3), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_wrap(~ measure, scales = "free_y") +
    #ggtitle(paste0("Region by region plot for ", stim)) +
    labs(
      title = "Regression Difference under Mismatch and Match conditions",
      y = "Regression prob. difference",
      x = "Sentence Region",
      color = "Agreement Type"
    ) +
  scale_x_continuous(breaks = c(1:5)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/Regression_results_interaction_in_synt.pdf"), device="pdf", height=5, width=8)

agg_l2 = df %>%
  group_by(type_l, subj_id, region, measure) %>%
    summarise(
      m = mean(value),
    ) %>%
  ungroup() %>%
  group_by(type_l, region, measure) %>%
  pivot_wider(
    names_from = type_l,
    values_from = m,
    names_prefix = "mean_"
  ) %>%
  # Calculate the difference between 'Mis' and 'Match'
  drop_na() %>%
  mutate(
    diff = mean_Modifying_Adj_Predictive_Adj - mean_Verb
  ) %>%
  group_by(region, measure) %>%
  summarise(
    m_diff = mean(diff),
    s = std.error(diff),
    lower = m_diff - 1.96 * s,
    upper = m_diff + 1.96 * s
  ) %>%
  ungroup()
`summarise()` has grouped output by 'type_l', 'subj_id', 'region'. You can override using the `.groups` argument.`summarise()` has grouped output by 'region'. You can override using the `.groups` argument.
# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_l2 %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("gaze_duration", "go_past_time", "total_duration")) %>%
  mutate(measure = factor(measure, levels = c("gaze_duration", "go_past_time", "total_duration"), labels=c("Gaze Duration", "Go Past Times", "Total Duration"))
         ) %>%

  ggplot(aes(x=region, y=m_diff, color = measure)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=lower-100, ymax=upper+100), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_wrap(~ measure, scales = "free_y") +
    labs(
      title = "Difference in RTs:\n Adj. (Modifying Adj. and Predictive Adj.) vs Verb",
      y = "Reading time difference (ms)",
      x = "Sentence Region",
      color = "Measure"
    ) +
  #coord_cartesian(ylim=c(0, 900)) +
  scale_x_continuous(breaks = c(1:5)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/RT_results_main_diff_in_lexical.pdf"), device="pdf", height=5, width=8)

# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_l2 %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("FPReg", "RegIn_incl")) %>%
  mutate(measure = factor(measure, levels = c("FPReg", "RegIn_incl"), labels=c("First Pass Regression out Prob.", "Regression in Prob."))) %>%

  ggplot(aes(x=region, y=m_diff, color = measure)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=-0.2, ymax=0.2), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_wrap(~ measure, scales = "free_y") +
    labs(
      title = "Difference in Regressions: \nAdj. (Modifying Adj. and Predictive Adj.) vs Verb",
      y = "Regression prob. difference",
      x = "Sentence Region",
      color = "Measure"
    ) +
  #coord_cartesian(ylim=c(0, 900)) +
  scale_x_continuous(breaks = c(1:5)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/Regression_results_main_diff_in_lexical.pdf"), device="pdf", height=5, width=8)

agg_l3 = df %>%
  group_by(type_l, gender_match, item_id, region, measure) %>%
    summarise(
      m = mean(value)
    ) %>%
  ungroup() %>%
  group_by(type_l, region, measure) %>%
  pivot_wider(
    names_from = gender_match,
    values_from = m,
    names_prefix = "mean_"
  ) %>%
  # Calculate the difference between 'Mis' and 'Match'
  drop_na() %>%
  mutate(
    diff = mean_Mis - mean_Match
  ) %>%
  group_by(type_l, region, measure) %>%
  summarise(
    m_diff = mean(diff),
    s = std.error(diff),
    lower = m_diff - 1.96 * s,
    upper = m_diff + 1.96 * s
  ) %>%
  ungroup()
`summarise()` has grouped output by 'type_l', 'gender_match', 'item_id', 'region'. You can override using the `.groups` argument.`summarise()` has grouped output by 'type_l', 'region'. You can override using the `.groups` argument.
# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_l3 %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("gaze_duration", "go_past_time", "total_duration")) %>%
  
  mutate(type_l = factor(type_l, levels = c("Modifying_Adj_Predictive_Adj", "Verb"), labels=c("Modifying Adj. & Predicative Adj.", "Verb"))) %>%
  mutate(measure = factor(measure, levels = c("gaze_duration", "go_past_time", "total_duration"), labels=c("Gaze Duration", "Go Past Times", "Total Duration"))) %>%

  ggplot(aes(x=region, y=m_diff, color = type_l)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=lower-100, ymax=upper+100), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_wrap(~ measure, scales = "free_y") +
    #ggtitle(paste0("Region by region plot for ", stim)) +
    labs(
      title = "RTs Difference under Mismatch and Match conditions",
      y = "Reading time difference (ms)",
      x = "Sentence Region",
      color = "Agreement Type"
    ) +
  scale_x_continuous(breaks = c(1:5)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/RT_results_interaction_in_lexical.pdf"), device="pdf", height=5, width=8)

agg_l3 %>%
  # filter(type_s %in% c("stim_adj", "stim_verb", "stim_pred_adj")) %>%
  filter(measure %in% c("FPReg", "RegIn_incl")) %>%
  
  mutate(type_l = factor(type_l, levels = c("Modifying_Adj_Predictive_Adj", "Verb"), labels=c("Modifying Adj. & Predicative Adj.", "Verb"))) %>%
  mutate(measure = factor(measure, levels = c("FPReg", "RegIn_incl"), labels=c("First Pass Regression out Prob.", "Regression in Prob."))) %>%

  ggplot(aes(x=region, y=m_diff, color = type_l)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=-0.3, ymax=0.3), color = NA, fill = "green", alpha=0.01) +
    geom_point() +
    geom_errorbar(aes(ymin=lower, ymax=upper), width = 0.2) +
    geom_line() +
    facet_wrap(~ measure, scales = "free_y") +
    #ggtitle(paste0("Region by region plot for ", stim)) +
    labs(
      title = "Regression Difference under Mismatch and Match conditions",
      y = "Regression prob. difference",
      x = "Sentence Region",
      color = "Agreement Type"
    ) +
  scale_x_continuous(breaks = c(1:5)) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/Regression_results_interaction_in_lexical.pdf"), device="pdf", height=5, width=8)

# Plot the reading times in each region broken down by stimulus type, reading measure and target gender

agg_sl2 %>%
  filter(measure %in% c("First Pass Regression out Prob.", "Regression in Prob.")) %>%
  ggplot(aes(x=region, y=m_diff, color = measure, group = Prediction, linetype = Prediction)) +
    geom_rect(aes(xmin=2.5, xmax=3.5, ymin=-0.2, ymax=0.2), color = NA, fill = "green", alpha=0.01) +
    geom_hline(yintercept = 0, color = "gray30") + 
    geom_point(aes(shape = Prediction), position = position_dodge(width = 0.3)) +
    geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2, position = position_dodge(width = 0.3)) +
    geom_line(position = position_dodge(width = 0.3)) +
    facet_wrap(~ measure, scales = "free_y") +
    labs(
      title  = "Feature-matching Mechanism vs Lexical category:\nReg_Prob.(Agreement - Concord) vs Reg_Prob.(Adj - Verb)",
      y = "Regression difference (ms)",
      x = "Sentence Region",
      linetype = "Prediction"
    ) +
  #coord_cartesian(ylim=c(0, 900)) +
  scale_x_continuous(breaks = c(1:5)) +
  scale_linetype_manual(values = c("solid", "dashed")) +
  guides(color = FALSE, shape = FALSE) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  )

ggsave(paste0("./images/Regression_main_diff_both_thoery.pdf"), device="pdf", height=4, width=16/3)

agg_sl3 %>%
  filter(measure %in% c("Gaze Duration", "Go Past Times", "Total Duration")) %>%
  ggplot(aes(x = region, y = m_diff, color = type, group = interaction(Prediction, type), linetype = Prediction)) +
    geom_rect(aes(xmin = 2.5, xmax = 3.5, ymin = lower - 100, ymax = upper + 100), color = NA, fill = "green", alpha = 0.01) +
    geom_hline(yintercept = 0, color = "gray30") + 
    geom_point(aes(shape = type)) +
    geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2) +
    geom_line() +
    geom_text(aes(label = annotation, y = annotation_y), vjust = 0, color = "black") +
    facet_grid(Prediction ~ measure, scales = "free_y") +
    labs(
      title = "Interaction between Grammaticality and \n Feature-match Mechanism / Lexical Category",
      y = "Reading time difference (Mis - Match)",
      x = "Sentence Region"
    ) +
  scale_x_continuous(breaks = c(1:5)) +
  scale_color_manual(values = c(
    "Concord" = "#56BCC2",
    "Agreement" = "#E77D72",
    "Adjective" = "#56BCC2",
    "Verb" = "#E77D72"
  )) +
  scale_shape_manual(values = c(
    "Concord" = 16, # Filled circle
    "Agreement" = 17, # Filled triangle
    "Adjective" = 16, # Filled circle
    "Verb" = 17 # Filled triangle
  )) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  ) +
  guides(
    linetype = "none",
    color = guide_legend(
      title = "Type",
      ncol = 4,
      byrow = TRUE,
      override.aes = list(
        linetype = c("solid", "solid", "dotdash", "dotdash"),
        shape = c(16, 17, 16, 17)
      )
    ),
    shape = guide_legend(
      title = "Type",
      ncol = 4,
      byrow = TRUE,
      override.aes = list(
        linetype = c("solid", "solid", "dotdash", "dotdash")
      )
    )
  )
ggsave(paste0("./images/RT_interaction_both_thoery.pdf"), device="pdf", height=5, width=8)

agg_sl3 %>%
  filter(measure %in% c("First Pass Regression out Prob.", "Regression in Prob.")) %>%
  ggplot(aes(x = region, y = m_diff, color = type, group = interaction(Prediction, type), linetype = Prediction)) +
    geom_rect(aes(xmin = 2.5, xmax = 3.5, ymin = lower - 0.2, ymax = upper + 0.2), color = NA, fill = "green", alpha = 0.01) +
    geom_hline(yintercept = 0, color = "gray30") + 
    geom_point(aes(shape = type)) +
    geom_errorbar(aes(ymin = lower, ymax = upper), width = 0.2) +
    geom_line() +
    # geom_text(aes(label = annotation, y = annotation_y), vjust = 0, color = "black") +
    facet_grid(Prediction ~ measure, scales = "free_y") +
    labs(
      title = "Interaction between Grammaticality and \n Feature-match Mechanism / Lexical Category",
      y = "Regression prob. difference (Mis - Match)",
      x = "Sentence Region"
    ) +
  scale_x_continuous(breaks = c(1:5)) +
  scale_color_manual(values = c(
    "Concord" = "#56BCC2",
    "Agreement" = "#E77D72",
    "Adjective" = "#56BCC2",
    "Verb" = "#E77D72"
  )) +
  scale_shape_manual(values = c(
    "Concord" = 16, # Filled circle
    "Agreement" = 17, # Filled triangle
    "Adjective" = 16, # Filled circle
    "Verb" = 17 # Filled triangle
  )) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(hjust = 0.5)
  ) +
  guides(
    linetype = "none",
    color = guide_legend(
      title = "Type",
      ncol = 4,
      byrow = TRUE,
      override.aes = list(
        linetype = c("solid", "solid", "dotdash", "dotdash"),
        shape = c(16, 17, 16, 17)
      )
    ),
    shape = guide_legend(
      title = "Type",
      ncol = 4,
      byrow = TRUE,
      override.aes = list(
        linetype = c("solid", "solid", "dotdash", "dotdash")
      )
    )
  )
ggsave(paste0("./images/Regression_interaction_both_thoery.pdf"), device="pdf", height=5, width=16/3)

LS0tCnRpdGxlOiAiRXhwbG9yYXRvcnkgQW5hbHlzaXMgZm9yIFJ1c3NpYW4gTW9UUiBSZWFkaW5nIERhdGEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKCgpgYGB7ciBsaWJyYXJpZXMsIGVjaG89VFJVRSwgcmVzdWx0cz0naGlkZScsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGV2YWw9VFJVRX0Kc2hoaCA8LSBzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMgIyBJdCdzIGEgbGlicmFyeSwgc28gc2hoaCEKCnNoaGgobGlicmFyeSggbWdjdiApKQpzaGhoKGxpYnJhcnkoZHBseXIpKQpzaGhoKGxpYnJhcnkoZ2dwbG90MikpCnNoaGgobGlicmFyeShsbWU0KSkKc2hoaChsaWJyYXJ5KHRpZHltdikpCnNoaGgobGlicmFyeShnYW1sc3MpKQpzaGhoKGxpYnJhcnkoZ3N1YmZuKSkKc2hoaChsaWJyYXJ5KGxtZXJUZXN0KSkKc2hoaChsaWJyYXJ5KHRpZHl2ZXJzZSkpCnNoaGgobGlicmFyeShib290KSkKc2hoaChsaWJyYXJ5KHJzYW1wbGUpKQpzaGhoKGxpYnJhcnkocGxvdHJpeCkpCnNoaGgobGlicmFyeShnZ3JlcGVsKSkKc2hoaChsaWJyYXJ5KG1nY3YpKQpzaGhoKGxpYnJhcnkoYnJtcykpCnNoaGgobGlicmFyeShiYXllc3Bsb3QpKQpzaGhoKGxpYnJhcnkodGlkeXIpKQpzaGhoKGxpYnJhcnkoY2FyKSkKc2hoaChsaWJyYXJ5KEhESW50ZXJ2YWwpKQpzaGhoKGxpYnJhcnkoZ3JpZEV4dHJhKSkKc2hoaChsaWJyYXJ5KHBvc3RlcmlvcikpCnNoaGgobGlicmFyeShyZWFkeGwpKQpzaGhoKGxpYnJhcnkoc3RyaW5ncikpCnNoaGgobGlicmFyeShsb28pKQoKc2hoaChsaWJyYXJ5KGNvZGEpKQpzaGhoKGxpYnJhcnkoY21kc3RhbnIpKQpzaGhoKGxpYnJhcnkocnN0YW4pKQpzaGhoKGxpYnJhcnkocnN0YW50b29scykpCgpyc3Rhbl9vcHRpb25zKGF1dG9fd3JpdGU9VFJVRSkKb3B0aW9ucyhtYy5jb3Jlcz1wYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkKcnN0YW5fb3B0aW9ucyhhdXRvX3dyaXRlID0gVFJVRSkKdGhlbWVfc2V0KHRoZW1lX2J3KCkpCm9wdGlvbnMoZGlnaXRzPTQpCm9wdGlvbnMoc2NpcGVuPTk5OSkKc2V0LnNlZWQoNDQ0KQoKYGBgCgojIFJlYWQgaW4gRVQgRGF0YQpgYGB7ciBFVC1EYXRhLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsIGV2YWw9VFJVRX0KZmlsZV9saXN0IDwtIGxpc3QuZmlsZXMoIi9Vc2Vycy9jdWkvRG9jdW1lbnRzL3V6aC9QaEQvUHJvamVjdHMvUnVzc2lhbl9BZ3JlZW1lbnQvcnVzc2lhbl9nZW5kZXIvcmVmL0V5ZXRyYWNraW5nLyIsIHBhdHRlcm4gPSAiKi54bHN4IiwgZnVsbC5uYW1lcyA9IFRSVUUpCmV0X3JhdyA8LSBmaWxlX2xpc3QgJT4lCiAgbGFwcGx5KHJlYWRfZXhjZWwpICU+JQogIGJpbmRfcm93cygpCgojIFZpZXcoZXRfcmF3KQpgYGAKCiMgUmVhZCBpbiBNb1RSIERhdGEKYGBge3IgTW9UUi1EYXRhLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsIGV2YWw9VFJVRX0KCiMgVGhlIHBhdGggdG8gdGhlIGRhdGEKZGF0YV9wYXRoIDwtICIuL2RhdGEvIgpkYXRhX25hbWVzIDwtIGxpc3QuZmlsZXMoZGF0YV9wYXRoKQoKIyBSZWFkIGluIHRoZSBkYXRhIGZyb20gZWFjaCBwYXJ0aWNpcGFudCBhbmQgYWRkIHRvIHRoZSBkYXRhIGZyYW1lCm1vdHJfZGYgPC0gZGF0YS5mcmFtZSgpCmZvcihuYW1lIGluIGRhdGFfbmFtZXMpewogIHN1YmogPC0gZ3N1YigicmVhZGVyXyIsICIiLCBnc3ViKCJfcmVhZGluZ19tZWFzdXJlcy5jc3YiLCAiIiwgbmFtZSkpCiAgdGVtcF9kZiA8LSByZWFkLmNzdihwYXN0ZTAoZGF0YV9wYXRoLCAiLyIsIG5hbWUpKSAlPiUgbXV0YXRlKHN1YmpfaWQgPSBzdWJqKQogIG1vdHJfZGYgPC0gcmJpbmQobW90cl9kZiwgdGVtcF9kZikKfSAKCm1vdHJfZGYgPC0gbW90cl9kZiAlPiUgbXV0YXRlKHdvcmRfbGVuID0gbmNoYXIod29yZCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdvcmRfbGVuZ3RoID0gc2NhbGUod29yZF9sZW4pWywxXSkgJT4lIAogIGdyb3VwX2J5KHN1YmpfaWQsIGl0ZW1faWQpICU+JQogIGFycmFuZ2Uoc3Vial9pZCwgaXRlbV9pZCkgJT4lCiAgbXV0YXRlKHdvcmRfbGVuX3ByZTEgPSBsYWcod29yZF9sZW5ndGgsIG4gPSAxKSwKICAgICAgICAgd29yZF9sZW5fcHJlMiA9IGxhZyh3b3JkX2xlbmd0aCwgbiA9IDIpKSAlPiUKICB1bmdyb3VwKCkKCgpWaWV3KG1vdHJfZGYpCgojIENsZWFuIHRoZSBkYXRhCmNsZWFuX2RmIDwtIG1vdHJfZGYgJT4lCiAgIyBmaWx0ZXIoc3Vial9pZCAhPSAxNzEpICU+JSAgICMgYWNjID0gMC44CiAgZmlsdGVyKCEgbGlzdCAlaW4lIGMoOTgsIDk5KSkgJT4lICMgZmlsdGVyIHByYWN0aWNlIGFuZCBmaWxsZXIgaXRlbXMKICBtdXRhdGUoc2tpcCA9IGlmZWxzZSh0b3RhbF9kdXJhdGlvbj09MCwgMSwgMCksCiAgICAgICAgIEZQUmVnID0gaWZlbHNlKGdhemVfZHVyYXRpb249PTAsIE5BLCBGUFJlZyksCiAgICAgICAgIEZQRml4ID0gaWZlbHNlKGdhemVfZHVyYXRpb249PTAsIE5BLCBGUEZpeCkpICU+JQogIGZpbHRlcihza2lwID09IDApICU+JQogIAogIGdhdGhlcihtZWFzdXJlLCB2YWx1ZSwgMTg6MjYpICU+JQogIG11dGF0ZSh0Z3RfemVybyA9IGlmX2Vsc2UobWVhc3VyZSAlaW4lIGMoImZpcnN0X2R1cmF0aW9uIiwgImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInJpZ2h0X2JvdW5kZWRfcnQiLCAidG90YWxfZHVyYXRpb24iKSAmIHZhbHVlID09IDAsIEYsIFQpKSAlPiUKICBmaWx0ZXIodGd0X3plcm8gIT0gRikgJT4lCiAgZHBseXI6OnNlbGVjdCgtdGd0X3plcm8sIC1jb25kX2lkLCAtc2tpcCwgLXdvcmRfbGVuKSAlPiUKICBtdXRhdGUoaXRlbV9pZCA9IGFzLmZhY3RvcihpdGVtX2lkKSwKICAgICAgICAgc3Vial9pZCA9IGFzLmZhY3RvcihzdWJqX2lkKSkgJT4lCiAgc3ByZWFkKG1lYXN1cmUsIHZhbHVlKSAlPiUKICBnYXRoZXIobWVhc3VyZSwgdmFsdWUsIGMoImZpcnN0X2R1cmF0aW9uIiwgImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInJpZ2h0X2JvdW5kZWRfcnQiLCAidG90YWxfZHVyYXRpb24iKSkgJT4lCiAgbXV0YXRlKG91dGxpZXIgPSB2YWx1ZSA+IChtZWFuKHZhbHVlLCBuYS5ybSA9IFRSVUUpICsgMyAqIHNkKHZhbHVlLCBuYS5ybSA9IFRSVUUpKSkgJT4lCiAgZmlsdGVyKG91dGxpZXIgPT0gRkFMU0UpICU+JQogIGRwbHlyOjpzZWxlY3QoLW91dGxpZXIpICU+JQogIHNwcmVhZChtZWFzdXJlLCB2YWx1ZSkgJT4lCiAgZ2F0aGVyKG1lYXN1cmUsIHZhbHVlLCAyMToyOSkgJT4lCgogIG11dGF0ZShjb25kID0gY2FzZV93aGVuKAogICAgdGFyZ2V0X2dlbmRlciA9PSAiTSIgJiBnZW5kZXJfbWF0Y2ggPT0gIk1pcyIgJiB0eXBlID09ICJzdGltX2FkaiIgfiAiYSIsCiAgICB0YXJnZXRfZ2VuZGVyID09ICJNIiAmIGdlbmRlcl9tYXRjaCA9PSAiTWlzIiAmIHR5cGUgPT0gInN0aW1fdmVyYiIgfiAiYiIsCiAgICAgdGFyZ2V0X2dlbmRlciA9PSAiTSIgJiBnZW5kZXJfbWF0Y2ggPT0gIk1pcyIgJiB0eXBlID09ICJzdGltX3ByZWRfYWRqIiB+ICJjIiwKICAgIHRhcmdldF9nZW5kZXIgPT0gIk0iICYgZ2VuZGVyX21hdGNoID09ICJNYXRjaCIgJiB0eXBlID09ICJzdGltX2FkaiIgfiAiZCIsCiAgICB0YXJnZXRfZ2VuZGVyID09ICJNIiAmIGdlbmRlcl9tYXRjaCA9PSAiTWF0Y2giICYgdHlwZSA9PSAic3RpbV92ZXJiIiB+ICJlIiwKICAgIHRhcmdldF9nZW5kZXIgPT0gIk0iICYgZ2VuZGVyX21hdGNoID09ICJNYXRjaCIgJiB0eXBlID09ICJzdGltX3ByZWRfYWRqIiB+ICJmIiwKICAgIHRhcmdldF9nZW5kZXIgPT0gIkYiICYgZ2VuZGVyX21hdGNoID09ICJNaXMiICYgdHlwZSA9PSAic3RpbV9hZGoiIH4gImciLAogICAgdGFyZ2V0X2dlbmRlciA9PSAiRiIgJiBnZW5kZXJfbWF0Y2ggPT0gIk1pcyIgJiB0eXBlID09ICJzdGltX3ZlcmIiIH4gImgiLAogICAgdGFyZ2V0X2dlbmRlciA9PSAiRiIgJiBnZW5kZXJfbWF0Y2ggPT0gIk1pcyIgJiB0eXBlID09ICJzdGltX3ByZWRfYWRqIiB+ICJpIiwKICAgIHRhcmdldF9nZW5kZXIgPT0gIkYiICYgZ2VuZGVyX21hdGNoID09ICJNYXRjaCIgJiB0eXBlID09ICJzdGltX2FkaiIgfiAiaiIsCiAgICB0YXJnZXRfZ2VuZGVyID09ICJGIiAmIGdlbmRlcl9tYXRjaCA9PSAiTWF0Y2giICYgdHlwZSA9PSAic3RpbV92ZXJiIiB+ICJrIiwKICAgIHRhcmdldF9nZW5kZXIgPT0gIkYiICYgZ2VuZGVyX21hdGNoID09ICJNYXRjaCIgJiB0eXBlID09ICJzdGltX3ByZWRfYWRqIiB+ICJsIiwKICAgIFRSVUUgfiBOQV9jaGFyYWN0ZXJfICMgVGhpcyBpcyB0aGUgZGVmYXVsdCBjYXNlIGlmIG5vbmUgb2YgdGhlIGFib3ZlIGNvbmRpdGlvbnMgYXJlIG1ldAogICkpICU+JQogIGRwbHlyOjpzZWxlY3QoLWxpc3QsIC1wYXJ0LCAtdHlwZV9pZCwgLW9yaWdfaXRlbV9udW1iZXIsIC1jYXNlLCAtYW5pbWFjeSwgLXJlc3BvbnNlX3RydWUsIC1yZXNwb25zZV9jaG9zZW4sIC1jb3JyZWN0bmVzcykgIyU+JQogICMgZHJvcF9uYSgpCgpjbGVhbl9kZiA8LSBjbGVhbl9kZiAlPiUKICBtdXRhdGUod29yZCA9IHN0cl9yZXBsYWNlX2FsbCh3b3JkLCAiXFwuIiwgIiIpKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKGxvZ19mcmVxID0gaWZlbHNlKHdvcmQgJWluJSBldF9yYXckSUFfTEFCRUwsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBldF9yYXckbGdfZnJlcXVlbmN5W21hdGNoKHdvcmQsIGV0X3JhdyRJQV9MQUJFTCldLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgTkFfcmVhbF8pKSAlPiUKICB1bmdyb3VwKCkKClZpZXcoY2xlYW5fZGYpCgpgYGAKCmBgYHtyIENPUlJFQ1RORVNTLCBldmFsPVRSVUV9CmNvcnJlY3RuZXNzIDwtIG1vdHJfZGYgJT4lIGRwbHlyOjpzZWxlY3QoaXRlbV9pZCwgY29uZF9pZCwgc3Vial9pZCwgY29ycmVjdG5lc3MpICU+JQogIGZpbHRlcihjb3JyZWN0bmVzcyAhPSA5OSkgJT4lIAogIGRpc3RpbmN0KCkKCmNvcnJlY3RuZXNzX3N1bW1hcnkgPC0gY29ycmVjdG5lc3MgJT4lCiAgZ3JvdXBfYnkoc3Vial9pZCkgJT4lCiAgc3VtbWFyaXNlKG1lYW5fY29ycmVjdG5lc3MgPSBtZWFuKGNvcnJlY3RuZXNzKSwKICAgICAgICAgICAgc2RfY29ycmVjdG5lc3MgPSBzZChjb3JyZWN0bmVzcyksCiAgICAgICAgICAgIGNvdW50ID0gbigpKQoKVmlldyhjb3JyZWN0bmVzc19zdW1tYXJ5KSAgICMgb25seSBzdWJqX2lkIDE3MSBnZXQgYWNjID0gMC44OyBvdGhlcnMgYWxsID4gMC44OAoKIyB3cml0ZS5jc3YoY29ycmVjdG5lc3Nfc3VtbWFyeSwgIi4vc3RhdHMvY29ycmVjdG5lc3Nfc3VtbWFyeS5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgoKIyMjIFJFU0VBUkNIIFFVRVNUSU9OUzoKIDEuIEFyZSBSVHMgZGlmZmVyZW50IGluIGdlbmRlci1tYXRjaCB2ZXJzdXMgZ2VuZGVyLW1pc21hdGNoIHNlbnRlbmNlcz8KID09PiBtYWluIGVmZmVjdCBvZiBncmFtbWF0aWNhbGl0eSAoZ2VuZGVyIG1hdGNoIG9yIG5vdCkKIAogMi4gQXJlIFJUcyBkaWZmZXJlbnQgaW4gTWFzY3VsaW5lIHZlcnN1cyBGZW1pbmluZSBzZW50ZW5jZSBjb25kaXRpb25zPwogPT0+IG1haW4gZWZmZWN0IG9mIGdlbmRlciBvZiB0YXJnZXQgd29yZAogCiAzLiBBcmUgUlRzIGFmZmVjdGVkIGJ5IHNlbnRlbmNlIHR5cGUgKHdoZXRoZXIgZGlmZmVyZW50IGxleGljYWwgY2F0ZWdvcmllcyBvZiB0aGUgYWdyZWVpbmcgZWxlbWVudCB3aWxsIG1ha2UgdGhlIHByb2Nlc3NpbmcgbW9yZSBkaWZmaWN1bHQgb3Igbm90KT8gLS0+IEFESihhZGogKyBwcmVfYWRqKSB2LnMuIFZFUkIgCiA9PT4gbWFpbiBlZmZlY3Qgb2YgbGV4aWNhbCB0eXBlIG9mIHNlbnRlbmNlcy4gCiAKIDQuIEFyZSBSVHMgYWZmZWN0ZWQgYnkgc2VudGVuY2UgdHlwZSAod2hldGhlciBhZ3JlZWluZyBlbGVtZW50IGluc3RhbnRpYXRlcyBpbnRlcm5hbCB2LnMuIGV4dGVybmFsIGFncmVlbWVudCB3aWxsIG1ha2UgYSBkaWZmZXJlbmNlIGluIHByb2Nlc3NpbmcgZGlmZmljdWx0eSk/IC0tPiBpbnRlcm5hbCAobW9kaWZ5aW5nIGFkamVjdGl2ZSkgdi5zLiBleHRlcm5hbCAodmVyYiBvciBwcmVkaWNhdGl2ZSBhZGplY3RpdmUpCiA9PT4gbWFpbiBlZmZlY3Qgb2Ygc3ludGF4IHR5cGUgb2Ygc2VudGVuY2VzLgogCiA1LiBEb2VzIHRoZSBncmFtbWF0aWNhbGl0eSBlZmZlY3Qgd2l0aGluIGVhY2ggbGV4aWNhbCBzZW50ZW5jZSB0eXBlIGRpZmZlciBmcm9tIGVhY2ggb3RoZXI/IC0tPiBXaGV0aGVyIHRoZSBlZmZlY3Qgb2YgZ3JhbW1hdGljYWxpdHkgZGVwZW5kcyBvbiB0aGUgbGV4aWNhbCB0eXBlIG9mIHRoZSBzZW50ZW5jZSAoQURKPyBWRVJCPykKID09PiBpbnRlcmFjdGlvbiBiZXR3ZWVuIGdyYW1tYXRpY2FsaXR5IGFuZCBsZXhpY2FsIHNlbnRlbmNlIHR5cGUKIAogNi5Eb2VzIHRoZSBncmFtbWF0aWNhbGl0eSBlZmZlY3Qgd2l0aGluIGVhY2ggc3ludGF4IHNlbnRlbmNlIHR5cGUgZGlmZmVyIGZyb20gZWFjaCBvdGhlcj8gLS0+IFdoZXRoZXIgdGhlIGVmZmVjdCBvZiBncmFtbWF0aWNhbGl0eSBkZXBlbmRzIG9uIHRoZSBzeW50YXggdHlwZSBvZiB0aGUgc2VudGVuY2UgKGludGVybmFsPyBleHRlcm5hbD8pCiA9PT4gaW50ZXJhY3Rpb24gYmV0d2VlbiBncmFtbWF0aWNhbGl0eSBhbmQgc3ludGF4IHNlbnRlbmNlIHR5cGUKIAogNy4gRG9lcyB0aGUgKHBvc3NpYmxlKSBkaWZmZXJlbmNlIGluIHRoZSBzZW5zaXRpdml0eSB0byB0aGUgZ3JhbW1hdGljYWxpdHkgbWFuaXB1bGF0aW9uIG9mIAogICAgIE1hc2N1bGluZSB2ZXJzdXMgRmVtaW5pbmUgY29uZGl0aW9ucyBkaWZmZXIgYmV0d2VlbiBsZXhpY2FsIHNlbnRlbmNlIHR5cGVzIChBREogdi5zLiBWRVJCKT8KID09PiAzLXdheSBpbnRlcmFjdGlvbiBiZXR3ZWVuIGdyYW1tYXRpY2FsaXR5LCBnZW5kZXIgYW5kIGxleGljYWwgc2VudGVuY2UgdHlwZQogCiA4LiBEb2VzIHRoZSAocG9zc2libGUpIGRpZmZlcmVuY2UgaW4gdGhlIHNlbnNpdGl2aXR5IHRvIHRoZSBncmFtbWF0aWNhbGl0eSBtYW5pcHVsYXRpb24gb2YgCiAgICAgTWFzY3VsaW5lIHZlcnN1cyBGZW1pbmluZSBjb25kaXRpb25zIGRpZmZlciBiZXR3ZWVuIHN5bnRheCBzZW50ZW5jZSB0eXBlcyAoaW50ZXJuYWwgdi5zLiBleHRlcm5hbCk/CiA9PT4gMy13YXkgaW50ZXJhY3Rpb24gYmV0d2VlbiBncmFtbWF0aWNhbGl0eSwgZ2VuZGVyIGFuZCBzeW50YXggc2VudGVuY2UgdHlwZQoKCiMgY29udHJhc3QgY29kaW5nCmBgYHtyIGZhY3Rvcml6ZSwgZWNobz1UUlVFLCBldmFsPVRSVUV9CiMgY2hlY2sgY29uZGl0aW9ucwpjbGVhbl9kZiRjb25kIDwtIGZhY3RvcihjbGVhbl9kZiRjb25kKQpzdW1tYXJ5KGNsZWFuX2RmJGNvbmQpCmBgYAoKCmBgYHtyIENvbnRyYXN0cy1jdXN0b21pemVkLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KY2xlYW5fZGYgPC0gY2xlYW5fZGYgJT4lIAogIG11dGF0ZSgKICAgICMtLS0tLS0tLS0tLS0tLS0tLS0tLS0gbWFpbiBlZmZlY3RzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgR3JhbSA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdiJywgJ2MnLCAnZycsICdoJywgJ2knKSwgMS82LCAtMS82KSwgIyBNYWluIGVmZmVjdCBncmFtbWF0aWNhbGl0eSAKICAgIEdlbiA9IGlmZWxzZShjb25kICVpbiUgYygnYScsJ2InLCdjJywnZCcsJ2UnLCAnZicpLCAxLzYsIC0xLzYpLCAjIE1haW4gZWZmZWN0IGdlbmRlcgogICAgVHlwTCA9IGlmZWxzZShjb25kICVpbiUgYygnYScsJ2MnLCdkJywnZicsICdnJywgJ2knLCAnaicsICdsJyksIDEvOCwgLTEvNCksICMgTWFpbiBlZmZlY3Qgb2Ygc2VudGVuY2UgdHlwZSAoYXAgdnMgdikKICAgIFR5cFMgPSBpZmVsc2UoY29uZCAlaW4lIGMoJ2EnLCAnZCcsICdnJywgJ2onKSwgMS80LCAtMS84KSwgIyBNYWluIGVmZmVjdCBvZiBzZW50ZW5jZSB0eXBlIChhIHZzIHB2KQogICAgCiAgICAjLS0tLS0tLS0tLS0tLS0tLS0tLS0tIDIgd2F5IGludGVyZWN0aW9uIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgIyBHcmFtX3hfVHlwTCA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdjJywgJ2knKSwgMS84LAogICAgIyAgICAgICAgICAgICAgICAgIGlmZWxzZShjb25kICVpbiUgYygnZCcsICdmJywgJ2wnKSwgLTEvOCwKICAgICMgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb25kICVpbiUgYygnZScsICdrJyksIDEvNCwgLTEvNCkpKSwgIyBHcmFtbWF0aWNhbGl0eSB4IHR5cGUgKGFwIHYpCiAgICAKICAgICMgR3JhbV94X1R5cFMgPSBpZmVsc2UoY29uZCAlaW4lIGMoJ2UnLCAnZicsICdrJywgJ2wnKSwgMS84LAogICAgIyAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29uZCAlaW4lIGMoJ2InLCAnYycsICdoJywgJ2knKSwgLTEvOCwKICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShjb25kICVpbiUgYygnYScsICdnJyksIDEvNCwgLTEvNCkpKSwgIyBHcmFtbWF0aWNhbGl0eSB4IHR5cGUgKGFwIHYpCiAgICAKICAgIEdyYW1feF9UeXBMID0gaWZlbHNlKGNvbmQgJWluJSBjKCdhJywgJ2MnLCAnZycsICdpJywgJ2UnLCAnaycpLCAxLzIsIC0xLzIpLCAjIEdyYW1tYXRpY2FsaXR5IHggdHlwZSAoYXAgdikKICAgIEdyYW1feF9UeXBTID0gaWZlbHNlKGNvbmQgJWluJSBjKCdhJywgJ2cnLCAnZScsICdmJywgJ2snLCAnbCcpLCAxLzIsIC0xLzIpLCAjIEdyYW1tYXRpY2FsaXR5IHggdHlwZSAoYSBwdikKCiAgICBHcmFtX1R5cExfTSA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdjJywgJ2UnKSwgMS8yLCAKICAgICAgICAgICAgICAgICAgICBpZmVsc2UoY29uZCAlaW4lIGMoJ2InLCAnZCcsICdmJyksIC0xLzIsIDApKSwgIyBncmFtIHggdHlwbChhcCB2KV9NCiAgICBHcmFtX1R5cFNfTSA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdlJywgJ2YnKSwgMS8yLCAKICAgICAgICAgICAgICAgIGlmZWxzZShjb25kICVpbiUgYygnYicsICdjJywgJ2QnKSwgLTEvMiwgMCkpLCAjIGdyYW0geCB0eXBzKGEgcHYpX00KICAgIEdyYW1fVHlwTF9GID0gaWZlbHNlKGNvbmQgJWluJSBjKCdnJywgJ2knLCAnaycpLCAxLzIsIAogICAgICAgICAgICAgICAgaWZlbHNlKGNvbmQgJWluJSBjKCdoJywgJ2onLCAnbCcpLCAtMS8yLCAwKSksICMgZ3JhbSB4IHR5cGwoYXAgdilfRgogICAgR3JhbV9UeXBTX0YgPSBpZmVsc2UoY29uZCAlaW4lIGMoJ2EnLCAnZScsICdmJyksIDEvMiwgCiAgICAgICAgICAgICAgICBpZmVsc2UoY29uZCAlaW4lIGMoJ2InLCAnYycsICdkJyksIC0xLzIsIDApKSwgIyBncmFtIHggdHlwcyhhIHB2KV9GCiAgICAKICAgICMtLS0tLS0tLS0tLS0tLS0tLS0tLS0gMyB3YXkgaW50ZXJlY3Rpb24gLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICBHcmFtX3hfR2VuX3hfVHlwTCA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdjJywgJ2UnLCAnaCcsICdqJywgJ2wnKSwgMS8yLCAtMS8yKSwgIyBnZW4geCB0eXAxKGFwIHYpIHggZ3JhbQogICAgR3JhbV94X0dlbl94X1R5cFMgPSBpZmVsc2UoY29uZCAlaW4lIGMoJ2EnLCAnZScsICdmJywgJ2gnLCAnaScsICdqJyksIDEvMiwgLTEvMiksICMgZ2VuIHggdHlwMShhcCB2KSB4IGdyYW0KICAgIAogICAgIy0tLS0tLS0tLS0tLS0tLS0tLS0tLSBXaXRoaW4gZ3JhbW1hdGljYWxpdHkgdHlwZSBlZmZlY3RzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgVHlwX01pcyA9IGlmZWxzZShjb25kICVpbiUgYygnYScsICdjJywgJ2cnLCAnaScpLCAxLzQsCiAgICAgICAgICAgICAgaWZlbHNlKGNvbmQgJWluJSBjKCdiJywgJ2gnKSwgLTEvMiwgMCkpLCAgIyB0eXBlX01pcwogICAgVHlwX01hdGNoID0gaWZlbHNlKGNvbmQgJWluJSBjKCdkJywgJ2YnLCAnaicsICdsJyksIDEvNCwKICAgICAgICAgICAgICAgICAgaWZlbHNlKGNvbmQgJWluJSBjKCdlJywgJ2snKSwgLTEvMiwgMCkpICAjIHR5cGVfTWF0Y2gKICApICU+JSBzcHJlYWQobWVhc3VyZSwgdmFsdWUpICU+JQogICMgZmlsdGVyKHdvcmRfbnIgPT0gMykKICBmaWx0ZXIoQU9JX2lkID09ICJSMyIpCiAgCmNsZWFuX2RmCmBgYAoKYGBge3IgQ29udHJhc3RzLWZ1Y2hzLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KY2xlYW5fZGYkdGFyZ2V0X2dlbmRlciA8LSBmYWN0b3IoY2xlYW5fZGYkdGFyZ2V0X2dlbmRlcikgICAgIyBGLCBNCmNsZWFuX2RmJGdlbmRlcl9tYXRjaCA8LSBmYWN0b3IoY2xlYW5fZGYkZ2VuZGVyX21hdGNoKSAgICAgICMgTWF0Y2gsIE1pc21hdGNoCmNsZWFuX2RmJHR5cGUgPC0gZmFjdG9yKGNsZWFuX2RmJHR5cGUpICAgICAgICAgICAgICAgICAgICAgICMgYWRqLCBwcmVfYWRqLCB2ZXJiCgpYX0NfYmFyMSA8LSBjb250ci5zdW0oMikKWF9DX2JhcjIgPC0gY29udHIuc3VtKDMpCgpjb250cmFzdHMoY2xlYW5fZGYkdGFyZ2V0X2dlbmRlcik8LSBYX0NfYmFyMQpjb250cmFzdHMoY2xlYW5fZGYkZ2VuZGVyX21hdGNoKTwtIFhfQ19iYXIxCmNvbnRyYXN0cyhjbGVhbl9kZiR0eXBlKTwtIFhfQ19iYXIyCgojIyBDaGVjayBjb250cmFzdHMKIyBjb250cmFzdHMoY2xlYW5fZGYkdGFyZ2V0X2dlbmRlcikKIyBjb250cmFzdHMoY2xlYW5fZGYkZ2VuZGVyX21hdGNoKQojIGNvbnRyYXN0cyhjbGVhbl9kZiR0eXBlKSAgICAjIFRoZSBjb250cmFzdCBpcyBmb3I6IGgwIC0+IGdyYW5kIG1lYW47IGgxIC0+IGFkai1ncmFuZCBtZWFuOyBoMiAtPiBwcmUtZ3JhbiBtZWFuCgpgYGAKCmBgYHtyIGZ1Y2hzX21vZGVscywgZWNobz1UUlVFLCBldmFsPUZBTFNFLCBtZXNzYWdlPVRSVUV9CmZ1Y2hzX3N0YXRzX2RmID0gZGF0YS5mcmFtZSgpCm1lYXN1cmVfdHlwZXMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIsIAogICAgICAgICAgICAgICAgICAiRlBSZWciLCAiUmVnSW5faW5jbCIpCgpmb3IgKG1lYXMgaW4gbWVhc3VyZV90eXBlcyl7CiAgcHJpbnQocGFzdGUoIkZpdHRpbmcgbW9kZWwgZm9yOiIsIG1lYXMpKQogIAogIGlmIChtZWFzICVpbiUgYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iKSl7CiAgICAgIG1vZGVsIDwtIGNsZWFuX2RmICU+JSBmaWx0ZXIoIWlzLm5hKC5kYXRhW1ttZWFzXV0pKSAgJT4lIAogICAgICAgICMgbXV0YXRlKGxvZ19tZWFzID0gbG9nKC5kYXRhW1ttZWFzXV0pKSAlPiUKICAgICAgICBsbWVyKGFzLmZvcm11bGEocGFzdGUoImxvZygiLCBtZWFzLCAiKSB+IGdlbmRlcl9tYXRjaCAqIHR5cGUgKyB0YXJnZXRfZ2VuZGVyICsgd29yZF9sZW5ndGggKyB3b3JkX2xlbl9wcmUxICsgd29yZF9sZW5fcHJlMiArIGxvZ19mcmVxICsgCiAgICAgICAgICAgICgxICsgZ2VuZGVyX21hdGNoIHwgc3Vial9pZCkgKyAoMSB8IGl0ZW1faWQpIikpLCAKICAgICAgICAgICAgZGF0YSA9IC4sIFJFTUwgPSBGKQogICAgICBjb2VmcyA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMKICAgICAgdGVtcF9yZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgICAgICAgbWVhc3VyZSA9IG1lYXMsCiAgICAgICAgYmV0YSA9IGMoImJfMCIsICJiX0dyYW0iLCAiYl9hZGoiLCAiYl9wcmVkX2FkaiIsICJiX2ZlbSIsICJiX2xlbiIsICJiX2xlbl9wcmUxIiwgImJfbGVuX3ByZTIiLCAiYl9mcmVxIiwgImJfR3JhbV94X2FkaiIsICJiX0dyYW1feF9wcmVkX2FkaiIpLAogICAgICAgIGJ2YWwgPSBjb2Vmc1ssICJFc3RpbWF0ZSJdLAogICAgICAgIHB2YWwgPSBjb2Vmc1ssICJQcig+fHR8KSJdCiAgICAgICkKICB9ZWxzZXsKICAgICAgbW9kZWwgPC0gY2xlYW5fZGYgJT4lIGZpbHRlcighaXMubmEoLmRhdGFbW21lYXNdXSkpICAlPiUgCiAgICAgICAgZ2xtZXIoYXMuZm9ybXVsYShwYXN0ZShtZWFzLCAifiBnZW5kZXJfbWF0Y2ggKiB0eXBlICsgICgxIHwgc3Vial9pZCkiKSksIAogICAgICAgICAgICBkYXRhID0gLiwgZmFtaWx5PWJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkKICAgICAgY29lZnMgPC0gc3VtbWFyeShtb2RlbCkkY29lZmZpY2llbnRzCiAgICAgIHRlbXBfcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogICAgICAgIG1lYXN1cmUgPSBtZWFzLAogICAgICAgIGJldGEgPSBjKCJiXzAiLCAiYl9HcmFtIiwgImJfYWRqIiwgImJfcHJlZF9hZGoiLCAiYl9HcmFtX3hfYWRqIiwgImJfR3JhbV94X3ByZWRfYWRqIiksCiAgICAgICAgYnZhbCA9IGNvZWZzWywgIkVzdGltYXRlIl0sCiAgICAgICAgcHZhbCA9IGNvZWZzWywgIlByKD58enwpIl0KICAgICAgICApCiAgfQogICAgZnVjaHNfc3RhdHNfZGYgPSByYmluZChmdWNoc19zdGF0c19kZiwgdGVtcF9yZXN1bHRzKQp9CgpmdWNoc19zdGF0c19kZiA9IGZ1Y2hzX3N0YXRzX2RmICU+JQogIG11dGF0ZShzaWcgPSBpZl9lbHNlKHB2YWwgPCAwLjA1LCAiU0lHIiwgaWZlbHNlKHB2YWwgPCAuMSwgIi4iLCAiIikpKQoKIyBWaWV3KGZ1Y2hzX3N0YXRzX2RmKQojIHdyaXRlLmNzdihmdWNoc19zdGF0c19kZiwgIi4vc3RhdHMvZnVjaHNfcmVwbGljYXRlcy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKCmBgYAoKYGBge3IgbmV3X2xtZXJfbW9kZWxzLCBlY2hvPVRSVUUsIGV2YWw9RkFMU0UsIG1lc3NhZ2U9VFJVRX0Kc3RhdHNfZGYgPSBkYXRhLmZyYW1lKCkKbWVhc3VyZV90eXBlcyA9IGMoImZpcnN0X2R1cmF0aW9uIiwgImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiwgCiAgICAgICAgICAgICAgICAgICJGUFJlZyIsICJSZWdJbl9pbmNsIgogICAgICAgICAgICAgICAgICApCgpmb3IgKG1lYXMgaW4gbWVhc3VyZV90eXBlcyl7CiAgcHJpbnQocGFzdGUoIkZpdHRpbmcgbW9kZWwgZm9yOiIsIG1lYXMpKQogIAogIGlmIChtZWFzICVpbiUgYygiZmlyc3RfZHVyYXRpb24iLCAiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iKSl7CiAgICAgIG1vZGVsIDwtIGNsZWFuX2RmICU+JSBmaWx0ZXIoIWlzLm5hKC5kYXRhW1ttZWFzXV0pKSAgJT4lIAogICAgICAgIGxtZXIoYXMuZm9ybXVsYShwYXN0ZSgibG9nKCIsIG1lYXMsICIpIH4gR3JhbSArIEdlbiArIFR5cEwgKyBUeXBTICsgR3JhbV94X1R5cEwgKyBHcmFtX3hfVHlwUyArIEdyYW1feF9HZW5feF9UeXBMICsgR3JhbV94X0dlbl94X1R5cFMgKyAKICAgICAgICAgICAgKDEgfCBpdGVtX2lkKSArICgxICsgR3JhbSB8IHN1YmpfaWQpIikpLCAKICAgICAgICAgICAgZGF0YSA9IC4sIFJFTUwgPSBGKQogICAgICBjb2VmcyA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMKICAgICAgdGVtcF9yZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgICAgICAgbWVhc3VyZSA9IG1lYXMsCiAgICAgICAgYmV0YSA9IGMoImJfMCIsICJiX0dyYW0iLCAiYl9HZW4iLCAiYl9UeXBMIiwgImJfVHlwUyIsIAogICAgICAgICAgICAgICAgICJiX0dyYW1feF9UeXBMIiwgImJfR3JhbV94X1R5cFMiLCAiYl9HcmFtX3hfR2VuX3hfVHlwTCIsICJiX0dyYW1feF9HZW5feF9UeXBTIiksCiAgICAgICAgYnZhbCA9IGNvZWZzWywgIkVzdGltYXRlIl0sCiAgICAgICAgcHZhbCA9IGNvZWZzWywgIlByKD58dHwpIl0KICAgICAgKQogIH1lbHNlewogICAgICBtb2RlbCA8LSBjbGVhbl9kZiAlPiUgZmlsdGVyKCFpcy5uYSguZGF0YVtbbWVhc11dKSkgICU+JSAKICAgICAgICBnbG1lcihhcy5mb3JtdWxhKHBhc3RlKG1lYXMsICJ+IEdyYW0gKyBHcmFtX3hfVHlwTCArIEdyYW1feF9UeXBTICsgR3JhbV94X0dlbl94X1R5cEwgKyBHcmFtX3hfR2VuX3hfVHlwUyArIAogICAgICAgICAgICAoMSB8IGl0ZW1faWQpICsgKDEgfCBzdWJqX2lkKSIpKSwgCiAgICAgICAgICAgIGRhdGEgPSAuLCBmYW1pbHk9Ymlub21pYWwobGluayA9ICJsb2dpdCIpKQogICAgICBjb2VmcyA8LSBzdW1tYXJ5KG1vZGVsKSRjb2VmZmljaWVudHMKICAgICAgdGVtcF9yZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgICAgICAgbWVhc3VyZSA9IG1lYXMsCiAgICAgICAgYmV0YSA9IGMoImJfMCIsICJiX0dyYW0iLCAKICAgICAgICAgICAgICAgICAiYl9HcmFtX3hfVHlwTCIsICJiX0dyYW1feF9UeXBTIiwgImJfR3JhbV94X0dlbl94X1R5cEwiLCAiYl9HcmFtX3hfR2VuX3hfVHlwUyIpLAogICAgICAgIGJ2YWwgPSBjb2Vmc1ssICJFc3RpbWF0ZSJdLAogICAgICAgIHB2YWwgPSBjb2Vmc1ssICJQcig+fHp8KSJdCiAgICAgICAgKQogIH0KICAgIHN0YXRzX2RmID0gcmJpbmQoc3RhdHNfZGYsIHRlbXBfcmVzdWx0cykKfQoKc3RhdHNfZGYgPSBzdGF0c19kZiAlPiUKICBtdXRhdGUoc2lnID0gaWZfZWxzZShwdmFsIDwgMC4wNSwgIlNJRyIsIGlmZWxzZShwdmFsIDwgLjEsICIuIiwgIiIpKSkKClZpZXcoc3RhdHNfZGYpCgojIHdyaXRlLmNzdihzdGF0c19kZiwgIi4vc3RhdHMvc3RhdHNfbG1lcl9uZXcuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCgpgYGAKCiMgTW9kZWwgY29tcGFyaXNvbgpgYGB7cn0KbW9kZWxfY29tcGFyaXNvbl9kZiA9IGRhdGEuZnJhbWUoKQptZWFzdXJlX3R5cGVzID0gYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iLCAKICAgICAgICAgICAgICAgICAgIkZQUmVnIiwgIlJlZ0luX2luY2wiKQoKZm9yIChtZWFzIGluIG1lYXN1cmVfdHlwZXMpewogIHByaW50KHBhc3RlKCJDb21wYXJlIG1vZGVscyBmb3I6IiwgbWVhcykpCiAgICBpZiAobWVhcyAlaW4lIGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIikpewogICAgICAgIG1vZGVsX2wgPC0gY2xlYW5fZGYgJT4lIGZpbHRlcighaXMubmEoLmRhdGFbW21lYXNdXSkpICU+JQogICAgICAgIGxtZXIoYXMuZm9ybXVsYShwYXN0ZSgibG9nKCIsIG1lYXMsICIpIH4gIEdyYW0gKyBHZW4gKyBUeXBMICArIEdyYW1feF9UeXBMICsgR3JhbV94X0dlbl94X1R5cEwgKyAKICAgICAgICAgICAgKDEgfCBpdGVtX2lkKSArICgxICsgR3JhbSB8IHN1YmpfaWQpIikpLCBkYXRhID0gLiwgUkVNTCA9IEYpCgogICAgICAgIG1vZGVsX3MgPC0gY2xlYW5fZGYgJT4lIGZpbHRlcighaXMubmEoLmRhdGFbWyJnb19wYXN0X3RpbWUiXV0pKSAgJT4lIAogICAgICAgIGxtZXIoYXMuZm9ybXVsYShwYXN0ZSgibG9nKCIsIG1lYXMsICIpIH4gR3JhbSArIEdlbiArIFR5cFMgICsgR3JhbV94X1R5cFMgKyBHcmFtX3hfR2VuX3hfVHlwUyArIAogICAgICAgICAgICAoMSB8IGl0ZW1faWQpICsgKDEgKyBHcmFtIHwgc3Vial9pZCkiKSksIGRhdGEgPSAuLCBSRU1MID0gRikKICAgIH1lbHNlewogICAgICAgIG1vZGVsX2wgPC0gY2xlYW5fZGYgJT4lIGZpbHRlcighaXMubmEoLmRhdGFbW21lYXNdXSkpICAlPiUgCiAgICAgICAgZ2xtZXIoYXMuZm9ybXVsYShwYXN0ZShtZWFzLCAifiBHcmFtICsgR3JhbV94X1R5cEwgKyBHcmFtX3hfR2VuX3hfVHlwTCArCiAgICAgICAgICAgICgxIHwgaXRlbV9pZCkiKSksIAogICAgICAgICAgICBkYXRhID0gLiwgZmFtaWx5PWJpbm9taWFsKGxpbmsgPSAibG9naXQiKSkKICAgICAgICBtb2RlbF9zIDwtIGNsZWFuX2RmICU+JSBmaWx0ZXIoIWlzLm5hKC5kYXRhW1ttZWFzXV0pKSAgJT4lIAogICAgICAgIGdsbWVyKGFzLmZvcm11bGEocGFzdGUobWVhcywgIn4gR3JhbSArIEdyYW1feF9UeXBTICsgR3JhbV94X0dlbl94X1R5cFMgKwogICAgICAgICAgICAoMSB8IGl0ZW1faWQpIikpLCAKICAgICAgICAgICAgZGF0YSA9IC4sIGZhbWlseT1iaW5vbWlhbChsaW5rID0gImxvZ2l0IikpCiAgICB9CiAgCiAgICBhaWNfYmljX2NvbXBhcmlzb24gPC0gZGF0YS5mcmFtZSgKICAgICAgYERlcGVuZGVudCBWYXJpYWJsZWAgPSBtZWFzLAogICAgICBgTW9kZWwgVHlwZWAgPSBjKCJMIG1vZGVsIiwgIlMgbW9kZWwiKSwKICAgICAgQUlDID0gYyhBSUMobW9kZWxfbCksIEFJQyhtb2RlbF9zKSksCiAgICAgIEJJQyA9IGMoQklDKG1vZGVsX2wpLCBCSUMobW9kZWxfcykpKQogICAgbW9kZWxfY29tcGFyaXNvbl9kZiA9IHJiaW5kKG1vZGVsX2NvbXBhcmlzb25fZGYsIGFpY19iaWNfY29tcGFyaXNvbikKfQojIHdyaXRlLmNzdihtb2RlbF9jb21wYXJpc29uX2RmLCAiLi9zdGF0cy9tb2RlbF9jb21wYXJpc29uX2xtZXIuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpCmBgYAoKIyBGaXQgQmF5ZXNpYW4gbW9kZWxzCiMgZnVuY3Rpb24gZm9yIGNyZWF0aW5nIHN0YW4gZGF0YSBmb3JtYXQKYGBge3IgY3JlYXRlU3RhbkRhdCwgZWNobz1UUlVFLCBldmFsPVRSVUV9CmNyZWF0ZVN0YW5EYXQ8LWZ1bmN0aW9uKGQsIGR2LGZvcm0pewogIAogIHN1YmogPC0gYXMuaW50ZWdlcihmYWN0b3IoZCRzdWJqX2lkKSkKICBOX3N1YmogPC0gbGVuZ3RoKHVuaXF1ZShzdWJqKSkKICBpdGVtIDwtIGFzLmludGVnZXIoZmFjdG9yKGQkaXRlbV9pZCkpCiAgTl9pdGVtcyA8LSBsZW5ndGgodW5pcXVlKGl0ZW0pKQogIFggPC0gdW5uYW1lKG1vZGVsLm1hdHJpeChmb3JtLCBkKSkgIAogIGF0dHIoWCwgd2hpY2g9ImFzc2lnbiIpIDwtIE5VTEwKICAKICBzdGFuRGF0IDwtIGxpc3QoTiA9IG5yb3coWCksICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgUCA9IG5jb2woWCksICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgbl91ID0gbmNvbChYKSwgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIG5fdyA9IG5jb2woWCksICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIFggPSBYLCAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICBaX3UgPSBYLCAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgIFpfdyA9IFgsICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICBKID0gTl9zdWJqLCAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgSyA9IE5faXRlbXMsCiAgICAgICAgICAgICAgICAgIGR2ID0gZHYsICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgc3ViaiA9IHN1YmosCiAgICAgICAgICAgICAgICAgIGl0ZW0gPSBpdGVtKQogIHN0YW5EYXQKfQpgYGAKCgpgYGB7ciBzdGFuX2dhemVfZHVyYXRpb24sIGVjaG89VFJVRSwgZXZhbD1GYWxzZX0Kc3Rhbl9nZCA8LSBjcmVhdGVTdGFuRGF0KGQ9c3Vic2V0KGNsZWFuX2RmLCAhaXMubmEoY2xlYW5fZGYkZ2F6ZV9kdXJhdGlvbikpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm09YXMuZm9ybXVsYSgifjErR3JhbStHZW4rVHlwTCtUeXBTK0dyYW1feF9UeXBMK0dyYW1feF9UeXBTK0dyYW1feF9HZW5feF9UeXBMK0dyYW1feF9HZW5feF9UeXBTIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2PXN1YnNldChjbGVhbl9kZiwgIWlzLm5hKGNsZWFuX2RmJGdhemVfZHVyYXRpb24pKSRnYXplX2R1cmF0aW9uKQoKbTFfZ2QgPC0gc3RhbihmaWxlID0gInN0YW4vbWF4TW9kZWwxLnN0YW4iLCAKICAgICAgICAgICAgICAgIGRhdGEgPSBzdGFuX2dkLAogICAgICAgICAgICAgICAgaXRlciA9IDQwMDAsIAogICAgICAgICAgICAgICAgY2hhaW5zID0gNCwKICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhPTAuOTkpKQpzYXZlUkRTKG0xX2dkLCBmaWxlID0gIm1vZGVsL20xX2dkMi5yZHMiKQpgYGAKCgpgYGB7ciBzdGFuX2dvX3Bhc3RfdGltZSwgZWNobz1UUlVFLCBldmFsPUZhbHNlfQpzdGFuX2dwdCA8LSBjcmVhdGVTdGFuRGF0KGQ9c3Vic2V0KGNsZWFuX2RmLCAhaXMubmEoY2xlYW5fZGYkZ29fcGFzdF90aW1lKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybT1hcy5mb3JtdWxhKCJ+MStHcmFtK0dlbitUeXBMK1R5cFMrR3JhbV94X1R5cEwrR3JhbV94X1R5cFMrR3JhbV94X0dlbl94X1R5cEwrR3JhbV94X0dlbl94X1R5cFMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHY9c3Vic2V0KGNsZWFuX2RmLCAhaXMubmEoY2xlYW5fZGYkZ29fcGFzdF90aW1lKSkkZ29fcGFzdF90aW1lKQoKIyBzYW1wbGUgZnJvbSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uLgptMV9ncHQgPC0gc3RhbihmaWxlID0gInN0YW4vbWF4TW9kZWwxLnN0YW4iLCAKICAgICAgICAgICAgICAgIGRhdGEgPSBzdGFuX2dwdCwKICAgICAgICAgICAgICAgIGl0ZXIgPSA0MDAwLCAKICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsCiAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YT0wLjk5KSkKc2F2ZVJEUyhtMV9ncHQsIGZpbGUgPSAibW9kZWwvbTFfZ3B0Mi5yZHMiKQpgYGAKCgpgYGB7ciBzdGFuX3RvdGFsX2R1cmF0aW9uLCBlY2hvPVRSVUUsIGV2YWw9RmFsc2V9CnN0YW5fdGQgPC0gY3JlYXRlU3RhbkRhdChkPXN1YnNldChjbGVhbl9kZiwgIWlzLm5hKGNsZWFuX2RmJHRvdGFsX2R1cmF0aW9uKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybT1hcy5mb3JtdWxhKCJ+MStHcmFtK0dlbitUeXBMK1R5cFMrR3JhbV94X1R5cEwrR3JhbV94X1R5cFMrR3JhbV94X0dlbl94X1R5cEwrR3JhbV94X0dlbl94X1R5cFMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHY9c3Vic2V0KGNsZWFuX2RmLCAhaXMubmEoY2xlYW5fZGYkdG90YWxfZHVyYXRpb24pKSR0b3RhbF9kdXJhdGlvbikKCiMgc2FtcGxlIGZyb20gcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbi4KbTFfdGQgPC0gc3RhbihmaWxlID0gInN0YW4vbWF4TW9kZWwxLnN0YW4iLCAKICAgICAgICAgICAgICAgIGRhdGEgPSBzdGFuX3RkLAogICAgICAgICAgICAgICAgaXRlciA9IDQwMDAsIAogICAgICAgICAgICAgICAgY2hhaW5zID0gNCwKICAgICAgICAgICAgICAgIGNvbnRyb2wgPSBsaXN0KGFkYXB0X2RlbHRhPTAuOTkpKQpzYXZlUkRTKG0xX3RkLCBmaWxlID0gIm1vZGVsL20xX3RkMi5yZHMiKQpgYGAKCiMgYmluYXJ5IGR2CmBgYHtyIHN0YW5fRlBSZWcsIGVjaG89VFJVRSwgZXZhbD1GYWxzZX0Kc3Rhbl9mcHJlZyA8LSBjcmVhdGVTdGFuRGF0KGQ9c3Vic2V0KGNsZWFuX2RmLCAhaXMubmEoY2xlYW5fZGYkRlBSZWcpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtPWFzLmZvcm11bGEoIn4xK0dyYW0rR2VuK1R5cEwrVHlwUytHcmFtX3hfVHlwTCtHcmFtX3hfVHlwUytHcmFtX3hfR2VuX3hfVHlwTCtHcmFtX3hfR2VuX3hfVHlwUyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj1zdWJzZXQoY2xlYW5fZGYsICFpcy5uYShjbGVhbl9kZiRGUFJlZykpJEZQUmVnKQoKIyBzYW1wbGUgZnJvbSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uLgptMV9mcHJlZyA8LSBzdGFuKGZpbGUgPSAic3Rhbi9sb2dpdE1vZGVsMS5zdGFuIiwgCiAgICAgICAgICAgICAgICBkYXRhID0gc3Rhbl9mcHJlZywKICAgICAgICAgICAgICAgIGl0ZXIgPSA0MDAwLCAKICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsCiAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YT0wLjk5KSkKc2F2ZVJEUyhtMV9mcHJlZywgZmlsZSA9ICJtb2RlbC9tMV9mcHJlZzIucmRzIikKYGBgCgoKYGBge3Igc3Rhbl9SZWdpbl9pbmNsLCBlY2hvPVRSVUUsIGV2YWw9RmFsc2V9CnN0YW5fcmVnaW4gPC0gY3JlYXRlU3RhbkRhdChkPXN1YnNldChjbGVhbl9kZiwgIWlzLm5hKGNsZWFuX2RmJFJlZ0luX2luY2wpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtPWFzLmZvcm11bGEoIn4xK0dyYW0rR2VuK1R5cEwrVHlwUytHcmFtX3hfVHlwTCtHcmFtX3hfVHlwUytHcmFtX3hfR2VuX3hfVHlwTCtHcmFtX3hfR2VuX3hfVHlwUyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj1zdWJzZXQoY2xlYW5fZGYsICFpcy5uYShjbGVhbl9kZiRSZWdJbl9pbmNsKSkkUmVnSW5faW5jbCkKCiMgc2FtcGxlIGZyb20gcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbi4KbTFfcmVnaW4gPC0gc3RhbihmaWxlID0gInN0YW4vbG9naXRNb2RlbDEuc3RhbiIsIAogICAgICAgICAgICAgICAgZGF0YSA9IHN0YW5fcmVnaW4sCiAgICAgICAgICAgICAgICBpdGVyID0gNDAwMCwgCiAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LAogICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGE9MC45OSkpCnNhdmVSRFMobTFfcmVnaW4sIGZpbGUgPSAibW9kZWwvbTFfcmVnaW4yLnJkcyIpCmBgYAoKCiMgRXhhbWluZSBmaXR0ZWQgc3RhbiBtb2RlbHMKYGBge3IgTW9kZWxfZXhhbWluYXRpb24sIGVjaG89VFJVRSwgZXZhbD1GYWxzZX0KIyBjaGFuZ2UgbTFfZ2QucmRzIHRvIG90aGVyIG1vZGVscyB0byBjaGVjayB0aGVtCgptMV9nZCA8LSByZWFkUkRTKCJtb2RlbC9tMV9mcHJlZy5yZHMiKQoKIyBjaGVjayBwYXJhbXMKc3VtbWFyeShtMV9nZCwgcGFycyA9IGMoJ2JldGFbMV0nLCAnYmV0YVsyXScsICdiZXRhWzNdJywgJ2JldGFbNF0nLCAnYmV0YVs1XScsICdiZXRhWzZdJywgJ2JldGFbN10nLCAnYmV0YVs4XScsICdiZXRhWzldJykpCgojIGNoZWNrIGNvbnZlcmdlbmNlCnRyYWNlcGxvdChtMV9nZCwgcGFycyA9IGMoImJldGEiKSkKCiMgY2hlY2sgcHJlZGljdHMgLS0+IHBvc3RlcmlvciBwYXJhbWV0ZXIgZGlzdHIuCnlfcG9zdGVyaW9yIDwtIGV4dHJhY3QobTFfZ2QpIAp5X3Bvc3RlcmlvciRiZXRhWywxXSAjaW50ZXJjZXB0CnlfcG9zdGVyaW9yJGJldGFbLDJdICNHcmFtCnlfcG9zdGVyaW9yJGJldGFbLDNdICNHZW4KeV9wb3N0ZXJpb3IkYmV0YVssNF0gI1R5cEwKeV9wb3N0ZXJpb3IkYmV0YVssNV0gI1R5cFMKeV9wb3N0ZXJpb3IkYmV0YVssNl0gI0dyYW1feF9UeXBMCnlfcG9zdGVyaW9yJGJldGFbLDddICNHcmFtX3hfVHlwUwoKIyBjaGVjayBwcmVkaWN0cyAtLT4gcG9zdGVyaW9yIHBhcmFtZXRlciBkaXN0ci4gYmFjayBpbiBub3JtYWwgc3BhY2UKcHN0X2dyYW0gPC0geV9wb3N0ZXJpb3IkR3JhbQpwc3RfZ3JhbQpkZW5zaXR5X2dyYW0gPC0gZGVuc2l0eShwc3RfZ3JhbSkKcGxvdChkZW5zaXR5X3Bsb3QsIG1haW4gPSAiRGVuc2l0eSBQbG90IG9mIHBzdF9ncmFtIiwgeGxhYiA9ICJwc3RfZ3JhbSB2YWx1ZXMiLCB5bGFiID0gIkRlbnNpdHkiLCBjb2wgPSAicmVkIikKCnBzdF9nZW4gPC0geV9wb3N0ZXJpb3IkR2VuCnBzdF9nZW4KZGVuc2l0eV9nZW4gPC0gZGVuc2l0eShwc3RfZ2VuKQpwbG90KGRlbnNpdHlfZ2VuLCBtYWluID0gIkRlbnNpdHkgUGxvdCBvZiBwc3RfZ2VuIiwgeGxhYiA9ICJwc3RfZ2VuIHZhbHVlcyIsIHlsYWIgPSAiRGVuc2l0eSIsIGNvbCA9ICJyZWQiKQoKcHN0X3R5cGwgPC0geV9wb3N0ZXJpb3IkVHlwTApwc3RfdHlwbApkZW5zaXR5X3R5cGwgPC0gZGVuc2l0eShwc3RfdHlwbCkKcGxvdChkZW5zaXR5X3R5cGwsIG1haW4gPSAiRGVuc2l0eSBQbG90IG9mIHBzdF90eXBsIiwgeGxhYiA9ICJwc3RfdHlwbCB2YWx1ZXMiLCB5bGFiID0gIkRlbnNpdHkiLCBjb2wgPSAicmVkIikKCnBzdF90eXBzIDwtIHlfcG9zdGVyaW9yJFR5cFMKcHN0X3R5cHMKZGVuc2l0eV90eXBzIDwtIGRlbnNpdHkocHN0X3R5cHMpCnBsb3QoZGVuc2l0eV90eXBzLCBtYWluID0gIkRlbnNpdHkgUGxvdCBvZiBwc3RfdHlwcyIsIHhsYWIgPSAicHN0X3R5cHMgdmFsdWVzIiwgeWxhYiA9ICJEZW5zaXR5IiwgY29sID0gInJlZCIpCgpwc3RfZ3JhbXh0eXBsIDwtIHlfcG9zdGVyaW9yJEdyYW1feF9UeXBMCnBzdF9ncmFteHR5cGwKZGVuc2l0eV9ncmFteHR5cGwgPC0gZGVuc2l0eShwc3RfZ3JhbXh0eXBsKQpwbG90KGRlbnNpdHlfZ3JhbXh0eXBsLCBtYWluID0gIkRlbnNpdHkgUGxvdCBvZiBwc3RfZ3JhbXh0eXBsIiwgeGxhYiA9ICJwc3RfZ3JhbXh0eXBsIHZhbHVlcyIsIHlsYWIgPSAiRGVuc2l0eSIsIGNvbCA9ICJyZWQiKQoKcHN0X2dyYW14dHlwcyA8LSB5X3Bvc3RlcmlvciRHcmFtX3hfVHlwUwpwc3RfZ3JhbXh0eXBzCmRlbnNpdHlfZ3JhbXh0eXBzIDwtIGRlbnNpdHkocHN0X2dyYW14dHlwcykKcGxvdChkZW5zaXR5X2dyYW14dHlwcywgbWFpbiA9ICJEZW5zaXR5IFBsb3Qgb2YgcHN0X2dyYW14dHlwcyIsIHhsYWIgPSAicHN0X2dyYW14dHlwcyB2YWx1ZXMiLCB5bGFiID0gIkRlbnNpdHkiLCBjb2wgPSAicmVkIikKCnBzdF9ncmFteGdlbnh0eXBsIDwtIHlfcG9zdGVyaW9yJEdyYW1feF9HZW5feF9UeXBMCnBzdF9ncmFteGdlbnh0eXBsCmRlbnNpdHlfZ3JhbXhnZW54dHlwbCA8LSBkZW5zaXR5KHBzdF9ncmFteGdlbnh0eXBsKQpwbG90KGRlbnNpdHlfZ3JhbXhnZW54dHlwbCwgbWFpbiA9ICJEZW5zaXR5IFBsb3Qgb2YgcHN0X2dyYW14Z2VueHR5cGwiLCB4bGFiID0gInBzdF9ncmFteGdlbnh0eXBsIHZhbHVlcyIsIHlsYWIgPSAiRGVuc2l0eSIsIGNvbCA9ICJyZWQiKQoKCnBzdF9ncmFteGdlbnh0eXBzIDwtIHlfcG9zdGVyaW9yJEdyYW1feF9HZW5feF9UeXBTCnBzdF9ncmFteGdlbnh0eXBzCmRlbnNpdHlfZ3JhbXhnZW54dHlwcyA8LSBkZW5zaXR5KHBzdF9ncmFteGdlbnh0eXBzKQpwbG90KGRlbnNpdHlfZ3JhbXhnZW54dHlwcywgbWFpbiA9ICJEZW5zaXR5IFBsb3Qgb2YgcHN0X2dyYW14Z2VueHR5cHMiLCB4bGFiID0gInBzdF9ncmFteGdlbnh0eXBzIHZhbHVlcyIsIHlsYWIgPSAiRGVuc2l0eSIsIGNvbCA9ICJyZWQiKQoKCiMgY2hlY2sgcG9zdGVyaW9yIHByZWRpY3RzIC0tPiB0aGUgZml0cyBsb29rcyB2ZXJ5IGdvb2QgLS0+IHN1c3Bpc2lvbiBvZiBvdmVyZml0PyAtLT4gY3YgdmFsaWRhdGlvbj8KcHJlZGljdHMgPC0geV9wb3N0ZXJpb3IkUHJlZGljdF9ydApkaW0ocHJlZGljdHMpICMgODAwMCB4IDEyNzEKeV90cnVlIDwtIHN1YnNldChjbGVhbl9kZiwgIWlzLm5hKGNsZWFuX2RmJEZQUmVnKSkkRlBSZWcKcHBjX2RlbnNfb3ZlcmxheSh5X3RydWUsIHlyZXAgPSBwcmVkaWN0c1sxOjIwMCwgXSkKCmBgYAoKYGBge3J9CmNhbGNfaHBkaSA8LSBmdW5jdGlvbihzYW1wbGVzLCBwcm9iID0gMC45NSkgewogIGlmKGxlbmd0aChzYW1wbGVzKSA8IDIpIHsgICMgQ2hlY2sgaWYgdGhlcmUgYXJlIHRvbyBmZXcgc2FtcGxlcyB0byBjYWxjdWxhdGUgYW4gaW50ZXJ2YWwKICAgIHJldHVybihjKGxvd2VyID0gTkEsIHVwcGVyID0gTkEpKQogIH0KICAjIEVuc3VyZSBzYW1wbGVzIGNhbiBiZSBjb252ZXJ0ZWQgdG8gYW4gbWNtYyBvYmplY3QKICB0cnlDYXRjaCh7CiAgICBocGRfaW50ZXJ2YWwgPC0gSFBEaW50ZXJ2YWwoYXMubWNtYyhzYW1wbGVzKSwgcHJvYiA9IHByb2IpCiAgICByZXR1cm4oYyhsb3dlciA9IGhwZF9pbnRlcnZhbFsxXSwgdXBwZXIgPSBocGRfaW50ZXJ2YWxbMl0pKQogIH0sIGVycm9yID0gZnVuY3Rpb24oZSkgewogICAgcmV0dXJuKGMobG93ZXIgPSBOQSwgdXBwZXIgPSBOQSkpICAjIFJldHVybiBOQSBpZiBhbnkgZXJyb3Igb2NjdXJzCiAgfSkKfQpgYGAKCiMgY29tcGlsZSBtb2RlbCByZXN1bHRzCmBgYHtyIGNvbXBpbGVfcmVzdHVscywgZWNobz1UUlVFLCBldmFsPVRSVUV9CnN0YXRzX2RmIDwtIGRhdGEuZnJhbWUoKQoKIyBEZWZpbmUgdGhlIG1lYXN1cmUgdHlwZXMgY29ycmVzcG9uZGluZyB0byB5b3VyIG1vZGVscwptZWFzdXJlX3R5cGVzIDwtIGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiwgIkZQUmVnIiwgIlJlZ0luX2luY2wiKQoKIyBMb29wIG92ZXIgZWFjaCBtZWFzdXJlIHR5cGUgdG8gcmVhZCB0aGUgY29ycmVzcG9uZGluZyBtb2RlbCBhbmQgZXh0cmFjdCBkYXRhCmZvciAobWVhcyBpbiBtZWFzdXJlX3R5cGVzKSB7CiAgaWYgKG1lYXMgPT0gImdhemVfZHVyYXRpb24iKSB7CiAgICAgIG0xIDwtIHJlYWRSRFMoIm1vZGVsL20xX2dkMi5yZHMiKQogICAgfSBlbHNlIGlmIChtZWFzID09ICJnb19wYXN0X3RpbWUiKSB7CiAgICAgIG0xIDwtIHJlYWRSRFMoIm1vZGVsL20xX2dwdDIucmRzIikKICAgIH0gZWxzZSBpZiAobWVhcyA9PSAidG90YWxfZHVyYXRpb24iKSB7CiAgICAgIG0xIDwtIHJlYWRSRFMoIm1vZGVsL20xX3RkMi5yZHMiKQogICAgfSBlbHNlIGlmIChtZWFzID09ICJGUFJlZyIpIHsKICAgICAgbTEgPC0gcmVhZFJEUygibW9kZWwvbTFfZnByZWcyLnJkcyIpCiAgICB9IGVsc2UgaWYgKG1lYXMgPT0gIlJlZ0luX2luY2wiKSB7CiAgICAgIG0xIDwtIHJlYWRSRFMoIm1vZGVsL20xX3JlZ2luMi5yZHMiKQogICAgfQoKICAjIEV4dHJhY3QgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMKICB5X3Bvc3RlcmlvciA8LSBleHRyYWN0KG0xKQogIGludGVyY2VwdCA8LSBleHAoeV9wb3N0ZXJpb3IkYmV0YVssMV0pCgogIGJldGFzIDwtIGMoImJfMCIsICJiX0dyYW0iLCAiYl9HZW4iLCAiYl9UeXBMIiwgImJfVHlwUyIsICJiX0dyYW1feF9UeXBMIiwgImJfR3JhbV94X1R5cFMiLCAiYl9HcmFtX3hfR2VuX3hfVHlwTCIsICJiX0dyYW1feF9HZW5feF9UeXBTIikKICBwb3N0ZXJpb3Jfc2FtcGxlcyA8LSBsaXN0KGludGVyY2VwdCwgeV9wb3N0ZXJpb3IkR3JhbSwgeV9wb3N0ZXJpb3IkR2VuLCB5X3Bvc3RlcmlvciRUeXBMLCB5X3Bvc3RlcmlvciRUeXBTLCB5X3Bvc3RlcmlvciRHcmFtX3hfVHlwTCwgeV9wb3N0ZXJpb3IkR3JhbV94X1R5cFMsIHlfcG9zdGVyaW9yJEdyYW1feF9HZW5feF9UeXBMLCB5X3Bvc3RlcmlvciRHcmFtX3hfR2VuX3hfVHlwUykKICAKICBocGRpXzk1IDwtIGxhcHBseShwb3N0ZXJpb3Jfc2FtcGxlcywgZnVuY3Rpb24oeCkgaGRpKHgsIGNyZWRNYXNzID0gMC45NSkpCiAgaHBkaV84OSA8LSBsYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIGZ1bmN0aW9uKHgpIGhkaSh4LCBjcmVkTWFzcyA9IDAuODkpKQoKICAjIFByZXBhcmUgdGhlIHJlc3VsdHMgZGF0YSBmcmFtZQogIHRlbXBfcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogICAgbWVhc3VyZSA9IHJlcChtZWFzLCBsZW5ndGgoYmV0YXMpKSwKICAgIGJldGEgPSBiZXRhcywKICAgIGJ2YWxfbWVhbiA9IHNhcHBseShwb3N0ZXJpb3Jfc2FtcGxlcywgbWVhbiksCiAgICBjcklfOTVfbG93ZXIgPSBzYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuMDI1KSksCiAgICBjcklfOTVfdXBwZXIgPSBzYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuOTc1KSksCiAgICBjcmxfODlfbG93ZXIgPSBzYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuMDU1KSksCiAgICBjcmxfODlfdXBwZXIgPSBzYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuOTQ1KSksCiAgICBocGRpXzk1X2xvd2VyID0gc2FwcGx5KGhwZGlfOTUsIGZ1bmN0aW9uKHgpIHhbMV0pLAogICAgaHBkaV85NV91cHBlciA9IHNhcHBseShocGRpXzk1LCBmdW5jdGlvbih4KSB4WzJdKSwKICAgIGhwZGlfODlfbG93ZXIgPSBzYXBwbHkoaHBkaV84OSwgZnVuY3Rpb24oeCkgeFsxXSksCiAgICBocGRpXzg5X3VwcGVyID0gc2FwcGx5KGhwZGlfODksIGZ1bmN0aW9uKHgpIHhbMl0pLAogICAgYnZhbF9tZWRpYW4gPSBzYXBwbHkocG9zdGVyaW9yX3NhbXBsZXMsIG1lZGlhbikKICApCgogICMgQXBwZW5kIHRoZSB0ZW1wX3Jlc3VsdHMgdG8gdGhlIHN0YXRzX2RmIGRhdGEgZnJhbWUKICBzdGF0c19kZiA8LSByYmluZChzdGF0c19kZiwgdGVtcF9yZXN1bHRzKQp9Cgp3cml0ZS5jc3Yoc3RhdHNfZGYsICIuL3N0YXRzL3N0YXRzX2JheWVzaWFuX25ldy5jc3YiLCByb3cubmFtZXMgPSBGQUxTRSkKYGBgCgojIyMgT0JTRVJWQVRJT05TOgoKZ3B0LCBnZCwgdGQsIHJlZzogCgoxLiBFZmZlY3RzIG9mIEdyYW1tYXRpY2FsaXR5IGFyZSBhbHdheXMgc2lnbmlmaWNhbnQuIC0tPiBUaGVyZSBhcmUgbWFpbiBlZmZlY3Qgb2YgZ3JhbW1hdGljYWxpdHkgKGdlbmRlciBtYXRjaCBvciBub3QpLgoyLiBFZmZlY3RzIG9mIGNvbmRUeXBTIGFyZSBzaWduaWZpY2FudCBvciBuZWFybHkgc2lnbmlmaWNhbnQuIC0tPiBWZXJ5IGxpa2VseSwgdGhlcmUgYXJlIG1haW4gZWZmZWN0IG9mIHN5bnRhY3RpYyBhZ3JlZW1lbnQgdHlwZSAoYWRqIHZzIHZlcmIgJiBwcmVkX2FkaikKCjMuIFRoZSBzaWduaWZpY2FuY2Ugb2YgY29uZFR5cEwgaXMgYWx3YXlzIHNtYWxsZXIgdGhhbiBjb25kVHlwUy4gSW4gQmF5ZXNpYW4sIHRoZSBjckkgb2YgYmV0YSBmb3IgVHlwTCAoZGlmZiBiZXR3ZWVuIGFkaiB2cyB2ZXJiKSBpcyBhbHdheXMgbGFyZ2VyIGFuZCAwIGlzIG1vcmUgdG8gdGhlIG1pZGRsZSBvZiBpdHMgZGlzdHJpYnV0aW9uLgoqIElmIGRvIHN1bSBjb250cmFzdCBmb3IgZWFjaCBsZXZlbCBvZiB0eXBlLCBwcmVkX2FkaiB0eXBlIGlzIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IGZyb20gdGhlIGdyYW5kIG1lYW4uCgo0LiBGb3IgZ2QsIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIFR5cFMgYW5kIEdyYW0gaXMgc2lnbmlmaWNhbnQuIEZvciB0ZCBhbmQgZ3B0LCBpdCBpcyBhbHNvIG5lYXIgdG8gc2lnbmlmaWNhbmNlIChvciAwIHRvIGJlIGluIHRoZSBuYXJyb3cgdGFpbCBvZiBpdHMgZGlzdHIuIGluIEJheWVzaWFuKS4gLS0+IGV4dGVybmFsIG9yIGludGVybmFsIGFncmVlbWVudCB3aWxsIGFmZmVjdCB0aGUgcHJvY2VzcyBvZiBtaXNtYXRjaGVzIGluIHNlbnRlbmNlLgoKNS4gSW50ZXJhY3Rpb24gYmV0d2VlbiBUeXBMIGFuZCBHcmFtIGlzIGZhciBmcm9tIHNpZ25pZmljYW5jZS4KCjYuIEluIHRkLCB0aGVyZSBhcmUgdGhyZWUgd2F5IGludGVyYWN0aW9uIGJldHdlZW4gVHlwTCAmIEdyYW0gJiBHZW4uIC0tPiBjb2luY2lkZW5jZT8gCgojIyMgQ09OQ0xVU0lPTjoKCjEuIExvbmdlciBydCBhbmQgbW9yZSByZWdyZXNzaW9ucyBpbiBlcnJvciBzZXRlbmNlcy4KMi4gTG9uZ2VyIHJ0IGFuZCBwb3NzaWJseSBtb3JlIHJlZ3Jlc3Npb25zIGluIGV4dGVybmFsIGFncmVlbWVudCB0aGFuIGludGVybmFsIG9uZXMuIC0tPiBleHRlcm5hbCBpcyBtb3JlIGRpZmZpY3VsdC4KMy4gQnV0IHJ0IGRpZmZlcmVuY2UgYmV0d2VlbiBtaXNtYXRjaCBhbmQgbWF0Y2ggaXMgYmlnZ2VyIGluIGludGVybmFsIHRoYW4gaW4gZXh0ZXJuYWwuIC0tPiBpbnRlcm5hbCBhZ3JlZW1lbnQga2luZCBvZiBhbXBsaWZ5IHRoZSBwcm9jZXNzaW5nIGRpZmZpY3VsdHkgaW4gbWlzbWF0Y2hlcy4gTWF5YmUgYmVjYXVzZSBleHRlcm5hbCBzZW50ZW5jZXMgYXJlIGFscmVhZHkgZGlmZmljdWx0LCBzbyB3aGVuIGNvbWJpbmVkIHdpdGggZXJyb3JzLCB0aGUgcnQgaXMgbm90IHRoYXQgZGlmZmVyZW50IGZyb20gaW4gY29ycmVjdCBzZW50ZW5jZS4gTWF5YmUgYmVjYXVzZSBwZW9wbGUgaGF2ZSB0aGVpciB1cGJvdW5kYXJ5IGZvciB0aGUgdGltZXMgdGhleSBzcGVuZCBvbiBkaWZmaWN1bHQgc2VudGVuY2VzPyAtLT4gb2J2aW91c2x5LCBydChkaWZmaWN1bHRfZXh0ZXJuYWxfdHlwZSArIGVycm9yX3NlbnRlbmNlKSA8IHJ0KGRpZmZpY3VsdF9leHRlcm5hbF90eXBlX3NlbnRlbmNlKSArIHJ0KGVycm9yX3NlbnRlbmNlKQoKCiMgQmF5ZXNpYW4gbW9kZWwgY29tcGFyaXNvbgpgYGB7ciBjb21wYXJlX2dvX3Bhc3RfdGltZSwgZWNobz1UUlVFLCBldmFsPUZhbHNlfQojIEV4Y2x1ZGUgb3V0bGllciBwb2ludHMgCmNsZWFuX2RhdGFfbGV4aWNhbCA8LSBjbGVhbl9kZiAlPiUgZmlsdGVyKHN1YmpfaWQgIT0gMTMxKQpjbGVhbl9kYXRhX3N5bnRheCA8LSBjbGVhbl9kZiAlPiUgZmlsdGVyKHN1YmpfaWQgIT0gMTMxKQoKIyBSZWZpdCB0aGUgbW9kZWxzIG9uIHRoZSBjbGVhbmVkIGRhdGEKbGV4aWNhbF9ncHRfY2xlYW4gPC0gY3JlYXRlU3RhbkRhdChkPXN1YnNldChjbGVhbl9kYXRhX2xleGljYWwsICFpcy5uYShjbGVhbl9kYXRhX2xleGljYWwkZ29fcGFzdF90aW1lKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybT1hcy5mb3JtdWxhKCJ+MStHcmFtK0dlbitUeXBMK0dyYW1feF9UeXBMK0dyYW1feF9HZW5feF9UeXBMIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR2PXN1YnNldChjbGVhbl9kYXRhX2xleGljYWwsICFpcy5uYShjbGVhbl9kYXRhX2xleGljYWwkZ29fcGFzdF90aW1lKSkkZ29fcGFzdF90aW1lKQoKIyBsZXhpY2FsX2dwdAojIHNhbXBsZSBmcm9tIHBvc3RlcmlvciBkaXN0cmlidXRpb24uCmxleGljYWxfZ3B0X2NsZWFuIDwtIHN0YW4oZmlsZSA9ICJzdGFuL01vZGVsY29tcGFyaXNvbi5zdGFuIiwgCiAgICAgICAgICAgICAgICBkYXRhID0gbGV4aWNhbF9ncHRfY2xlYW4sCiAgICAgICAgICAgICAgICBpdGVyID0gNDAwMCwgCiAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LAogICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGE9MC45OSkKICAgICAgICAgICAgICAgICkKIyBzYXZlUkRTKGxleGljYWxfZ3B0X2NsZWFuLCBmaWxlID0gIm1vZGVsL21vZGVsX2NvbXBhcmlzb24vbGV4aWNhbF9ncHRfY2xlYW4ucmRzIikKCnN5bnRheF9ncHRfY2xlYW4gPC0gY3JlYXRlU3RhbkRhdChkPXN1YnNldChjbGVhbl9kYXRhX3N5bnRheCwgIWlzLm5hKGNsZWFuX2RhdGFfc3ludGF4JGdvX3Bhc3RfdGltZSkpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm09YXMuZm9ybXVsYSgifjErR3JhbStHZW4rVHlwUytHcmFtX3hfVHlwUytHcmFtX3hfR2VuX3hfVHlwUyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdj1zdWJzZXQoY2xlYW5fZGF0YV9zeW50YXgsICFpcy5uYShjbGVhbl9kYXRhX3N5bnRheCRnb19wYXN0X3RpbWUpKSRnb19wYXN0X3RpbWUpCgojIGxleGljYWxfZ3B0CiMgc2FtcGxlIGZyb20gcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbi4Kc3ludGF4X2dwdF9jbGVhbiA8LSBzdGFuKGZpbGUgPSAic3Rhbi9Nb2RlbGNvbXBhcmlzb24uc3RhbiIsIAogICAgICAgICAgICAgICAgZGF0YSA9IHN5bnRheF9ncHRfY2xlYW4sCiAgICAgICAgICAgICAgICBpdGVyID0gNDAwMCwgCiAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LAogICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3QoYWRhcHRfZGVsdGE9MC45OSkpCiMgc2F2ZVJEUyhzeW50YXhfZ3B0X2NsZWFuLCBmaWxlID0gIm1vZGVsL21vZGVsX2NvbXBhcmlzb24vc3ludGF4X2dwdF9jbGVhbi5yZHMiKQoKIyBQZXJmb3JtIExPTyBvbiBjbGVhbmVkIG1vZGVscwpsb29fbGV4aWNhbF9jbGVhbiA8LSBsb28obGV4aWNhbF9ncHRfY2xlYW4pCmxvb19zeW50YXhfY2xlYW4gPC0gbG9vKHN5bnRheF9ncHRfY2xlYW4pCgojIENvbXBhcmUgdGhlIGNsZWFuZWQgbW9kZWxzCmxvb19jb21wYXJlKGxvb19sZXhpY2FsX2NsZWFuLCBsb29fc3ludGF4X2NsZWFuKQpgYGAKCiMgUExPVApgYGB7cn0KIyBDcmVhdGUgYW4gYWdncmVnYXRlIERGIHdpdGggbWVhbiBhbmQgOTUlIENJcyBmb3IgZWFjaCBjb25kaXRpb24gYW5kIHNlbnRlbmNlIHJlZ2lvbgoKZGYgPC0gbW90cl9kZiAlPiUKICAjIGZpbHRlcihzdWJqX2lkICE9IDE3MSkgJT4lICAgIyBhY2MgPSAwLjgKICBkcGx5cjo6c2VsZWN0KC13b3JkX2xlbiwgLXdvcmRfbGVuZ3RoLCAtd29yZF9sZW5fcHJlMSwgLXdvcmRfbGVuX3ByZTIpICU+JQogIGZpbHRlcighIGxpc3QgJWluJSBjKDk4LCA5OSkpICU+JSAjIGZpbHRlciBwcmFjdGljZSBhbmQgZmlsbGVyIGl0ZW1zCiAgbXV0YXRlKHNraXAgPSBpZmVsc2UodG90YWxfZHVyYXRpb24gIT0gMCwgMCwgMSksCiAgICAgICAgIEZQUmVnID0gaWZlbHNlKGdhemVfZHVyYXRpb249PTAsIE5BLCBGUFJlZyksCiAgICAgICAgIEZQRml4ID0gaWZlbHNlKGdhemVfZHVyYXRpb249PTAsIE5BLCBGUEZpeCkpICU+JQogIGZpbHRlcihza2lwID09IDApICU+JQogIAogIGdhdGhlcihtZWFzdXJlLCB2YWx1ZSwgMTg6MjYpICU+JQogIG11dGF0ZSh0Z3RfemVybyA9IGlmX2Vsc2UobWVhc3VyZSAlaW4lIGMoImZpcnN0X2R1cmF0aW9uIiwgImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInJpZ2h0X2JvdW5kZWRfcnQiLCAidG90YWxfZHVyYXRpb24iKSAmIHZhbHVlID09IDAsIEYsIFQpKSAlPiUKICBmaWx0ZXIodGd0X3plcm8gIT0gRikgJT4lCiAgZHJvcF9uYSgpICU+JQogIGRwbHlyOjpzZWxlY3QoLXRndF96ZXJvLCAtY29uZF9pZCwgLXNraXApICU+JQoKICAjIG11dGF0ZSh3b3JkX25yID0gaWZfZWxzZSh3b3JkX25yID4gNCwgNCwgYXMuZG91YmxlKHdvcmRfbnIpKSkgJT4lCiAgIyByZW5hbWUocmVnaW9uID0gd29yZF9ucikgJT4lCiAgIyBtdXRhdGUoQU9JX2lkID0gaWZfZWxzZShBT0lfaWQgJWluJSBjKCJSNSIsICJSNiIpLCAiUjQiLCBBT0lfaWQpKSAlPiUKICBtdXRhdGUocmVnaW9uID0gYXMuZG91YmxlKHN1YnN0cihBT0lfaWQsIDIsIDIpKSkgJT4lCiAgIyBtdXRhdGUocmVnaW9uID0gZmFjdG9yKHJlZ2lvbiwgbGV2ZWxzPWMoJzEnLCAnMicsICczJywgJzQnKSwgbGFiZWxzPWMoImNyaXRpY2FsIC0yIiwgImNyaXRpY2FsIC0xIiwgImNyaXRpY2FsIiwgImNyaXRpY2FsICsxIikpKSAlPiUKICBtdXRhdGUodHlwZV9zID0gaWZlbHNlKHR5cGUgJWluJSBjKCdzdGltX2FkaicpLCAiTW9kaWZ5aW5nX0FkaiIsICJQcmVkaWN0aXZlX0Fkal9WZXJiIiksCiAgICAgICAgIHR5cGVfbCA9IGlmZWxzZSh0eXBlICVpbiUgYygnc3RpbV92ZXJiJyksICJWZXJiIiwgIk1vZGlmeWluZ19BZGpfUHJlZGljdGl2ZV9BZGoiKQogICAgICAgICApICU+JQogIHNwcmVhZChtZWFzdXJlLCB2YWx1ZSkgJT4lCiAgZ2F0aGVyKG1lYXN1cmUsIHZhbHVlLCBjKCAiZmlyc3RfZHVyYXRpb24iLCAiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAicmlnaHRfYm91bmRlZF9ydCIsICJ0b3RhbF9kdXJhdGlvbiIpKSAlPiUKICBtdXRhdGUob3V0bGllciA9IHZhbHVlID4gKG1lYW4odmFsdWUsIG5hLnJtID0gVFJVRSkgKyAzICogc2QodmFsdWUsIG5hLnJtID0gVFJVRSkpKSAlPiUKICBmaWx0ZXIob3V0bGllciA9PSBGQUxTRSkgJT4lCiAgZHBseXI6OnNlbGVjdCgtb3V0bGllcikgJT4lCiAgc3ByZWFkKG1lYXN1cmUsIHZhbHVlKSAlPiUKICBkcm9wX25hKHRvdGFsX2R1cmF0aW9uKSAlPiUKICBnYXRoZXIobWVhc3VyZSwgdmFsdWUsIDIxOjI5KSAlPiUKICBmaWx0ZXIocmVnaW9uICVpbiVjKDIsIDMsIDQsIDUpKSAlPiUKICBkcm9wX25hKCkKICAKVmlldyhkZikKCmFnZ19zID0gZGYgJT4lCiAgZ3JvdXBfYnkodHlwZV9zLCBnZW5kZXJfbWF0Y2gsIHJlZ2lvbiwgbWVhc3VyZSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG0gPSBtZWFuKHZhbHVlKSwKICAgICAgcyA9IHN0ZC5lcnJvcih2YWx1ZSksCiAgICAgIGxvd2VyID0gbSAtIDEuOTYgKiBzLAogICAgICB1cHBlciA9IG0gKyAxLjk2ICogcwogICAgKSAlPiUKICB1bmdyb3VwKCkKCmFnZ19zCgoKYWdnX2FsbCA9IGRmICU+JQogIGdyb3VwX2J5KHR5cGUsIGdlbmRlcl9tYXRjaCwgcmVnaW9uLCBtZWFzdXJlKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbSA9IG1lYW4odmFsdWUpLAogICAgICBzID0gc3RkLmVycm9yKHZhbHVlKSwKICAgICAgbG93ZXIgPSBtIC0gMS45NiAqIHMsCiAgICAgIHVwcGVyID0gbSArIDEuOTYgKiBzCiAgICApICU+JQogIHVuZ3JvdXAoKQoKYWdnX2FsbAoKYGBgCgpgYGB7cn0KZnVjaHNfc3RhdHNfZGYgPC0gIHJlYWQuY3N2KCIuL3N0YXRzL2Z1Y2hzX3JlcGxpY2F0ZXNfbW90ci5jc3YiKQpWaWV3KGZ1Y2hzX3N0YXRzX2RmKQoKYGBgCgoKCmBgYHtyfQoKIyBQbG90IHRoZSByZWFkaW5nIHRpbWVzIGluIGVhY2ggcmVnaW9uIGJyb2tlbiBkb3duIGJ5IHN0aW11bHVzIHR5cGUsIHJlYWRpbmcgbWVhc3VyZSBhbmQgdGFyZ2V0IGdlbmRlcgoKYWdnX2FsbCAlPiUKICAjIGZpbHRlcih0eXBlX3MgJWluJSBjKCJzdGltX2FkaiIsICJzdGltX3ZlcmIiLCAic3RpbV9wcmVkX2FkaiIpKSAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIikpICU+JQogIAogIG11dGF0ZSh0eXBlID0gZmFjdG9yKHR5cGUsIGxldmVscyA9IGMoInN0aW1fYWRqIiwgInN0aW1fcHJlZF9hZGoiLCAic3RpbV92ZXJiIiksIGxhYmVscz1jKCJNb2RpZnlpbmcgQWRqLiIsICJQcmVkaWNhdGl2ZSBBZGouIiwgICJWZXJiIikpKSAlPiUKICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpLCBsYWJlbHM9YygiR2F6ZSBEdXJhdGlvbiIsICJHbyBQYXN0IFRpbWVzIiwgIlRvdGFsIER1cmF0aW9uIikpKSAlPiUKICAKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uLCB5PW0sIGNvbG9yID0gZ2VuZGVyX21hdGNoKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTIuNSwgeG1heD0zLjUsIHltaW49bG93ZXItMTAwLCB5bWF4PXVwcGVyKzEwMCksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYT0wLjAxKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3dlciwgeW1heD11cHBlciksIHdpZHRoID0gMC4yKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBmYWNldF9ncmlkKG1lYXN1cmV+dHlwZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgICMgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6NCwgbGFiZWxzID0gYygiY3JpdGljYWwgLTIiLCAiY3JpdGljYWwgLTEiLCAiY3JpdGljYWwiLCAiY3JpdGljYWwgKzEiKSkgKwogICAgI2dndGl0bGUocGFzdGUwKCJSZWdpb24gYnkgcmVnaW9uIHBsb3QgZm9yICIsIHN0aW0pKSArCiAgICB5bGFiKCJSZWFkaW5nIHRpbWUgKG1zKSIpICsKICAgIHhsYWIoIlNlbnRlbmNlIFJlZ2lvbiIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTWF0Y2giID0gIiM1NkJDQzIiLCAiTWlzIiA9ICIjRTc3RDcyIikpICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA5MDApKSArCiAgdGhlbWUoCiAgICAjIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUlRfcmVzdWx0c19hbGxfdHlwZXMucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTUsIHdpZHRoPTUpCgpgYGAKCmBgYHtyfQojIFBsb3QgdGhlIHJlYWRpbmcgdGltZXMgaW4gZWFjaCByZWdpb24gYnJva2VuIGRvd24gYnkgc3RpbXVsdXMgdHlwZSwgcmVhZGluZyBtZWFzdXJlIGFuZCB0YXJnZXQgZ2VuZGVyCgphZ2dfYWxsICU+JQogIGZpbHRlcihtZWFzdXJlICVpbiUgYygiRlBSZWciLCAiUmVnSW5faW5jbCIpKSAlPiUKICAKICBtdXRhdGUodHlwZSA9IGZhY3Rvcih0eXBlLCBsZXZlbHMgPSBjKCJzdGltX2FkaiIsICJzdGltX3ByZWRfYWRqIiwgInN0aW1fdmVyYiIpLCBsYWJlbHM9YygiTW9kaWZ5aW5nIEFkai4iLCAiUHJlZGljYXRpdmUgQWRqLiIsICAiVmVyYiIpKSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJGUFJlZyIsICJSZWdJbl9pbmNsIiksIGxhYmVscz1jKCJSZWdyLiBvdXQgUHJvYi4iLCAiUmVnci4gaW4gUHJvYi4iKSkpICU+JQoKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uLCB5PW0sIGNvbG9yID0gZ2VuZGVyX21hdGNoKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTIuNSwgeG1heD0zLjUsIHltaW49bG93ZXItMC4yLCB5bWF4PXVwcGVyKzAuMiksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYT0wLjAxKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3dlciwgeW1heD11cHBlciksIHdpZHRoID0gMC4yKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBmYWNldF9ncmlkKG1lYXN1cmV+dHlwZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICAgIHlsYWIoIlJlZ3Jlc3Npb24gUHJvYi4iKSArCiAgICB4bGFiKCJTZW50ZW5jZSBSZWdpb24iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk1hdGNoIiA9ICIjNTZCQ0MyIiwgIk1pcyIgPSAiI0U3N0Q3MiIpKSArCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgOTAwKSkgKwogIHRoZW1lKAogICAgIyBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUmVncmVzc2lvbl9yZXN1bHRzX2FsbF90eXBlcy5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9My40LCB3aWR0aD01KQpgYGAKCgpgYGB7cn0KCiMgUGxvdCB0aGUgcmVhZGluZyB0aW1lcyBpbiBlYWNoIHJlZ2lvbiBicm9rZW4gZG93biBieSBzdGltdWx1cyB0eXBlLCByZWFkaW5nIG1lYXN1cmUgYW5kIHRhcmdldCBnZW5kZXIKCmFnZ19zICU+JQogICMgZmlsdGVyKHR5cGVfcyAlaW4lIGMoInN0aW1fYWRqIiwgInN0aW1fdmVyYiIsICJzdGltX3ByZWRfYWRqIikpICU+JQogIGZpbHRlcihtZWFzdXJlICVpbiUgYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iKSkgJT4lCiAgCiAgbXV0YXRlKHR5cGVfcyA9IGZhY3Rvcih0eXBlX3MsIGxldmVscyA9IGMoIk1vZGlmeWluZ19BZGoiLCAiUHJlZGljdGl2ZV9BZGpfVmVyYiIpLCBsYWJlbHM9YygiTW9kaWZ5aW5nIEFkai4iLCAiUHJlZGljYXRpdmUgQWRqLiAmIFZlcmIiKSkpICU+JQogIG11dGF0ZShtZWFzdXJlID0gZmFjdG9yKG1lYXN1cmUsIGxldmVscyA9IGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiksIGxhYmVscz1jKCJHYXplIER1cmF0aW9uIiwgIkdvIFBhc3QgVGltZXMiLCAiVG90YWwgRHVyYXRpb24iKSkpICU+JQogIAogIGdncGxvdChhZXMoeD1yZWdpb24sIHk9bSwgY29sb3IgPSBnZW5kZXJfbWF0Y2gpKSArCiAgICBnZW9tX3JlY3QoYWVzKHhtaW49Mi41LCB4bWF4PTMuNSwgeW1pbj1sb3dlci0xMDAsIHltYXg9dXBwZXIrMTAwKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X2dyaWQobWVhc3VyZX50eXBlX3MsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICAjIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjQsIGxhYmVscyA9IGMoImNyaXRpY2FsIC0yIiwgImNyaXRpY2FsIC0xIiwgImNyaXRpY2FsIiwgImNyaXRpY2FsICsxIikpICsKICAgICNnZ3RpdGxlKHBhc3RlMCgiUmVnaW9uIGJ5IHJlZ2lvbiBwbG90IGZvciAiLCBzdGltKSkgKwogICAgeWxhYigiUmVhZGluZyB0aW1lIChtcykiKSArCiAgICB4bGFiKCJTZW50ZW5jZSBSZWdpb24iKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIk1hdGNoIiA9ICIjNTZCQ0MyIiwgIk1pcyIgPSAiI0U3N0Q3MiIpKSArCiAgI2Nvb3JkX2NhcnRlc2lhbih5bGltPWMoMCwgOTAwKSkgKwogIHRoZW1lKAogICAgIyBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIgogICkKCmdnc2F2ZShwYXN0ZTAoIi4vaW1hZ2VzL1JUX3Jlc3VsdHNfc3ludF9wb3NpdGlvbjIucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTUsIHdpZHRoPTUpCgpgYGAKYGBge3J9CiMgUGxvdCB0aGUgcmVhZGluZyB0aW1lcyBpbiBlYWNoIHJlZ2lvbiBicm9rZW4gZG93biBieSBzdGltdWx1cyB0eXBlLCByZWFkaW5nIG1lYXN1cmUgYW5kIHRhcmdldCBnZW5kZXIKCmFnZ19zICU+JQogIGZpbHRlcihtZWFzdXJlICVpbiUgYygiRlBSZWciLCAiUmVnSW5faW5jbCIpKSAlPiUKICAKICBtdXRhdGUodHlwZV9zID0gZmFjdG9yKHR5cGVfcywgbGV2ZWxzID0gYygiTW9kaWZ5aW5nX0FkaiIsICJQcmVkaWN0aXZlX0Fkal9WZXJiIiksIGxhYmVscz1jKCJNb2RpZnlpbmcgQWRqLiIsICJQcmVkaWNhdGl2ZSBBZGouICYgVmVyYiIpKSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJGUFJlZyIsICJSZWdJbl9pbmNsIiksIGxhYmVscz1jKCJSZWdyLiBvdXQgUHJvYi4iLCAiUmVnci4gaW4gUHJvYi4iKSkpICU+JQoKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uLCB5PW0sIGNvbG9yID0gZ2VuZGVyX21hdGNoKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTIuNSwgeG1heD0zLjUsIHltaW49bG93ZXItMC4yLCB5bWF4PXVwcGVyKzAuMiksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYT0wLjAxKSArCiAgICBnZW9tX3BvaW50KCkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1sb3dlciwgeW1heD11cHBlciksIHdpZHRoID0gMC4yKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBmYWNldF9ncmlkKG1lYXN1cmV+dHlwZV9zLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgeWxhYigiUmVncmVzc2lvbiBQcm9iLiIpICsKICAgIHhsYWIoIlNlbnRlbmNlIFJlZ2lvbiIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiTWF0Y2giID0gIiM1NkJDQzIiLCAiTWlzIiA9ICIjRTc3RDcyIikpICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA5MDApKSArCiAgdGhlbWUoCiAgICAjIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SZWdyZXNzaW9uX3Jlc3VsdHNfc3ludF9wb3NpdGlvbjIucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTMuNCwgd2lkdGg9NSkKYGBgCgoKCmBgYHtyfQphZ2dfczIgPSBkZiAlPiUKICBncm91cF9ieSh0eXBlX3MsIHN1YmpfaWQsIHJlZ2lvbiwgbWVhc3VyZSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG0gPSBtZWFuKHZhbHVlKSwKICAgICkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHR5cGVfcywgcmVnaW9uLCBtZWFzdXJlKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSB0eXBlX3MsCiAgICB2YWx1ZXNfZnJvbSA9IG0sCiAgICBuYW1lc19wcmVmaXggPSAibWVhbl8iCiAgKSAlPiUKICAjIENhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuICdNaXMnIGFuZCAnTWF0Y2gnCiAgZHJvcF9uYSgpICU+JQogIG11dGF0ZSgKICAgIGRpZmYgPSBtZWFuX1ByZWRpY3RpdmVfQWRqX1ZlcmIgLSBtZWFuX01vZGlmeWluZ19BZGoKICApICU+JQogIGdyb3VwX2J5KHJlZ2lvbiwgbWVhc3VyZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgbV9kaWZmID0gbWVhbihkaWZmKSwKICAgIHMgPSBzdGQuZXJyb3IoZGlmZiksCiAgICBsb3dlciA9IG1fZGlmZiAtIDEuOTYgKiBzLAogICAgdXBwZXIgPSBtX2RpZmYgKyAxLjk2ICogcwogICkgJT4lCiAgdW5ncm91cCgpCgojIFZpZXcoYWdnX3MyKQpgYGAKCmBgYHtyfQojIFBsb3QgdGhlIHJlYWRpbmcgdGltZXMgaW4gZWFjaCByZWdpb24gYnJva2VuIGRvd24gYnkgc3RpbXVsdXMgdHlwZSwgcmVhZGluZyBtZWFzdXJlIGFuZCB0YXJnZXQgZ2VuZGVyCgphZ2dfczIgJT4lCiAgIyBmaWx0ZXIodHlwZV9zICVpbiUgYygic3RpbV9hZGoiLCAic3RpbV92ZXJiIiwgInN0aW1fcHJlZF9hZGoiKSkgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpKSAlPiUKICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpLCBsYWJlbHM9YygiR2F6ZSBEdXJhdGlvbiIsICJHbyBQYXN0IFRpbWVzIiwgIlRvdGFsIER1cmF0aW9uIikpCiAgICAgICAgICkgJT4lCgogIGdncGxvdChhZXMoeD1yZWdpb24sIHk9bV9kaWZmLCBjb2xvciA9IG1lYXN1cmUpKSArCiAgICBnZW9tX3JlY3QoYWVzKHhtaW49Mi41LCB4bWF4PTMuNSwgeW1pbj1sb3dlci0xMDAsIHltYXg9dXBwZXIrMTAwKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBSVHM6IFxuRXh0ZXJuYWwgKFZlcmIgb3IgUHJlZGljYXRpdmUgQWRqLikgdnMgSW50ZXJuYWwgYWdyZWVtZW50IChNb2RpZnlpbmcgQWRqLikiLAogICAgICB5ID0gIlJlYWRpbmcgdGltZSBkaWZmZXJlbmNlIChtcykiLAogICAgICB4ID0gIlNlbnRlbmNlIFJlZ2lvbiIsCiAgICAgIGNvbG9yID0gIk1lYXN1cmUiCiAgICApICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA5MDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMTo1KSkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KQogICkKCmdnc2F2ZShwYXN0ZTAoIi4vaW1hZ2VzL1JUX3Jlc3VsdHNfbWFpbl9kaWZmX2luX3N5bnQucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTUsIHdpZHRoPTgpCmBgYAoKYGBge3J9CiMgUGxvdCB0aGUgcmVhZGluZyB0aW1lcyBpbiBlYWNoIHJlZ2lvbiBicm9rZW4gZG93biBieSBzdGltdWx1cyB0eXBlLCByZWFkaW5nIG1lYXN1cmUgYW5kIHRhcmdldCBnZW5kZXIKCmFnZ19zMiAlPiUKICAjIGZpbHRlcih0eXBlX3MgJWluJSBjKCJzdGltX2FkaiIsICJzdGltX3ZlcmIiLCAic3RpbV9wcmVkX2FkaiIpKSAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoIkZQUmVnIiwgIlJlZ0luX2luY2wiKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiRlBSZWciLCAiUmVnSW5faW5jbCIpLCBsYWJlbHM9YygiRmlyc3QgUGFzcyBSZWdyZXNzaW9uIG91dCBQcm9iLiIsICJSZWdyZXNzaW9uIGluIFByb2IuIikpKSAlPiUKCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbiwgeT1tX2RpZmYsIGNvbG9yID0gbWVhc3VyZSkpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yLjUsIHhtYXg9My41LCB5bWluPS0wLjIsIHltYXg9MC4yKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBSZWdyZXNzaW9uczogXG5FeHRlcm5hbCAoVmVyYiBvciBQcmVkaWNhdGl2ZSBBZGouKSB2cyBJbnRlcm5hbCBhZ3JlZW1lbnQgKE1vZGlmeWluZyBBZGopIiwKICAgICAgeSA9ICJSZWdyZXNzaW9uIGRpZmZlcmVuY2UgKG1zKSIsCiAgICAgIHggPSAiU2VudGVuY2UgUmVnaW9uIiwKICAgICAgY29sb3IgPSAiTWVhc3VyZSIKICAgICkgKwogICNjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDkwMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKQoKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUmVncmVzc2lvbl9yZXN1bHRzX21haW5fZGlmZl9pbl9zeW50LnBkZiIpLCBkZXZpY2U9InBkZiIsIGhlaWdodD01LCB3aWR0aD04KQpgYGAKCgpgYGB7cn0KCmFnZ19zMyA9IGRmICU+JQogIGdyb3VwX2J5KHR5cGVfcywgZ2VuZGVyX21hdGNoLCBpdGVtX2lkLCByZWdpb24sIG1lYXN1cmUpICU+JQogICAgc3VtbWFyaXNlKAogICAgICBtID0gbWVhbih2YWx1ZSkKICAgICkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHR5cGVfcywgcmVnaW9uLCBtZWFzdXJlKSAlPiUKICBwaXZvdF93aWRlcigKICAgIG5hbWVzX2Zyb20gPSBnZW5kZXJfbWF0Y2gsCiAgICB2YWx1ZXNfZnJvbSA9IG0sCiAgICBuYW1lc19wcmVmaXggPSAibWVhbl8iCiAgKSAlPiUKICAjIENhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuICdNaXMnIGFuZCAnTWF0Y2gnCiAgZHJvcF9uYSgpICU+JQogIG11dGF0ZSgKICAgIGRpZmYgPSBtZWFuX01pcyAtIG1lYW5fTWF0Y2gKICApICU+JQogIGdyb3VwX2J5KHR5cGVfcywgcmVnaW9uLCBtZWFzdXJlKSAlPiUKICBzdW1tYXJpc2UoCiAgICBtX2RpZmYgPSBtZWFuKGRpZmYpLAogICAgcyA9IHN0ZC5lcnJvcihkaWZmKSwKICAgIGxvd2VyID0gbV9kaWZmIC0gMS45NiAqIHMsCiAgICB1cHBlciA9IG1fZGlmZiArIDEuOTYgKiBzCiAgKSAlPiUKICB1bmdyb3VwKCkKClZpZXcoYWdnX3MzKQpgYGAKCmBgYHtyfQojIFBsb3QgdGhlIHJlYWRpbmcgdGltZXMgaW4gZWFjaCByZWdpb24gYnJva2VuIGRvd24gYnkgc3RpbXVsdXMgdHlwZSwgcmVhZGluZyBtZWFzdXJlIGFuZCB0YXJnZXQgZ2VuZGVyCgphZ2dfczMgJT4lCiAgIyBmaWx0ZXIodHlwZV9zICVpbiUgYygic3RpbV9hZGoiLCAic3RpbV92ZXJiIiwgInN0aW1fcHJlZF9hZGoiKSkgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpKSAlPiUKICAKICBtdXRhdGUodHlwZV9zID0gZmFjdG9yKHR5cGVfcywgbGV2ZWxzID0gYygiTW9kaWZ5aW5nX0FkaiIsICJQcmVkaWN0aXZlX0Fkal9WZXJiIiksIGxhYmVscz1jKCJNb2RpZnlpbmcgQWRqLiIsICJQcmVkaWNhdGl2ZSBBZGouICYgVmVyYiIpKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iKSwgbGFiZWxzPWMoIkdhemUgRHVyYXRpb24iLCAiR28gUGFzdCBUaW1lcyIsICJUb3RhbCBEdXJhdGlvbiIpKSkgJT4lCgogIGdncGxvdChhZXMoeD1yZWdpb24sIHk9bV9kaWZmLCBjb2xvciA9IHR5cGVfcykpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yLjUsIHhtYXg9My41LCB5bWluPWxvd2VyLTEwMCwgeW1heD11cHBlcisxMDApLCBjb2xvciA9IE5BLCBmaWxsID0gImdyZWVuIiwgYWxwaGE9MC4wMSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bG93ZXIsIHltYXg9dXBwZXIpLCB3aWR0aCA9IDAuMikgKwogICAgZ2VvbV9saW5lKCkgKwogICAgZmFjZXRfd3JhcCh+IG1lYXN1cmUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICAjZ2d0aXRsZShwYXN0ZTAoIlJlZ2lvbiBieSByZWdpb24gcGxvdCBmb3IgIiwgc3RpbSkpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIlJUcyBEaWZmZXJlbmNlIHVuZGVyIE1pc21hdGNoIGFuZCBNYXRjaCBjb25kaXRpb25zIiwKICAgICAgeSA9ICJSZWFkaW5nIHRpbWUgZGlmZmVyZW5jZSAobXMpIiwKICAgICAgeCA9ICJTZW50ZW5jZSBSZWdpb24iLAogICAgICBjb2xvciA9ICJBZ3JlZW1lbnQgVHlwZSIKICAgICkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDE6NSkpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkKICApCgpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SVF9yZXN1bHRzX2ludGVyYWN0aW9uX2luX3N5bnQucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTUsIHdpZHRoPTgpCmBgYAoKYGBge3J9CmFnZ19zMyAlPiUKICAjIGZpbHRlcih0eXBlX3MgJWluJSBjKCJzdGltX2FkaiIsICJzdGltX3ZlcmIiLCAic3RpbV9wcmVkX2FkaiIpKSAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoIkZQUmVnIiwgIlJlZ0luX2luY2wiKSkgJT4lCiAgCiAgbXV0YXRlKHR5cGVfcyA9IGZhY3Rvcih0eXBlX3MsIGxldmVscyA9IGMoIk1vZGlmeWluZ19BZGoiLCAiUHJlZGljdGl2ZV9BZGpfVmVyYiIpLCBsYWJlbHM9YygiTW9kaWZ5aW5nIEFkai4iLCAiUHJlZGljYXRpdmUgQWRqLiAmIFZlcmIiKSkpICU+JQogIG11dGF0ZShtZWFzdXJlID0gZmFjdG9yKG1lYXN1cmUsIGxldmVscyA9IGMoIkZQUmVnIiwgIlJlZ0luX2luY2wiKSwgbGFiZWxzPWMoIkZpcnN0IFBhc3MgUmVncmVzc2lvbiBvdXQgUHJvYi4iLCAiUmVncmVzc2lvbiBpbiBQcm9iLiIpKSkgJT4lCgogIGdncGxvdChhZXMoeD1yZWdpb24sIHk9bV9kaWZmLCBjb2xvciA9IHR5cGVfcykpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yLjUsIHhtYXg9My41LCB5bWluPS0wLjMsIHltYXg9MC4zKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgI2dndGl0bGUocGFzdGUwKCJSZWdpb24gYnkgcmVnaW9uIHBsb3QgZm9yICIsIHN0aW0pKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJSZWdyZXNzaW9uIERpZmZlcmVuY2UgdW5kZXIgTWlzbWF0Y2ggYW5kIE1hdGNoIGNvbmRpdGlvbnMiLAogICAgICB5ID0gIlJlZ3Jlc3Npb24gcHJvYi4gZGlmZmVyZW5jZSIsCiAgICAgIHggPSAiU2VudGVuY2UgUmVnaW9uIiwKICAgICAgY29sb3IgPSAiQWdyZWVtZW50IFR5cGUiCiAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKQoKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUmVncmVzc2lvbl9yZXN1bHRzX2ludGVyYWN0aW9uX2luX3N5bnQucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTUsIHdpZHRoPTgpCmBgYAoKYGBge3J9CmFnZ19sMiA9IGRmICU+JQogIGdyb3VwX2J5KHR5cGVfbCwgc3Vial9pZCwgcmVnaW9uLCBtZWFzdXJlKSAlPiUKICAgIHN1bW1hcmlzZSgKICAgICAgbSA9IG1lYW4odmFsdWUpLAogICAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkodHlwZV9sLCByZWdpb24sIG1lYXN1cmUpICU+JQogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IHR5cGVfbCwKICAgIHZhbHVlc19mcm9tID0gbSwKICAgIG5hbWVzX3ByZWZpeCA9ICJtZWFuXyIKICApICU+JQogICMgQ2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gJ01pcycgYW5kICdNYXRjaCcKICBkcm9wX25hKCkgJT4lCiAgbXV0YXRlKAogICAgZGlmZiA9IG1lYW5fTW9kaWZ5aW5nX0Fkal9QcmVkaWN0aXZlX0FkaiAtIG1lYW5fVmVyYgogICkgJT4lCiAgZ3JvdXBfYnkocmVnaW9uLCBtZWFzdXJlKSAlPiUKICBzdW1tYXJpc2UoCiAgICBtX2RpZmYgPSBtZWFuKGRpZmYpLAogICAgcyA9IHN0ZC5lcnJvcihkaWZmKSwKICAgIGxvd2VyID0gbV9kaWZmIC0gMS45NiAqIHMsCiAgICB1cHBlciA9IG1fZGlmZiArIDEuOTYgKiBzCiAgKSAlPiUKICB1bmdyb3VwKCkKClZpZXcoYWdnX2wyKQpgYGAKCmBgYHtyfQojIFBsb3QgdGhlIHJlYWRpbmcgdGltZXMgaW4gZWFjaCByZWdpb24gYnJva2VuIGRvd24gYnkgc3RpbXVsdXMgdHlwZSwgcmVhZGluZyBtZWFzdXJlIGFuZCB0YXJnZXQgZ2VuZGVyCgphZ2dfbDIgJT4lCiAgIyBmaWx0ZXIodHlwZV9zICVpbiUgYygic3RpbV9hZGoiLCAic3RpbV92ZXJiIiwgInN0aW1fcHJlZF9hZGoiKSkgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpKSAlPiUKICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIpLCBsYWJlbHM9YygiR2F6ZSBEdXJhdGlvbiIsICJHbyBQYXN0IFRpbWVzIiwgIlRvdGFsIER1cmF0aW9uIikpCiAgICAgICAgICkgJT4lCgogIGdncGxvdChhZXMoeD1yZWdpb24sIHk9bV9kaWZmLCBjb2xvciA9IG1lYXN1cmUpKSArCiAgICBnZW9tX3JlY3QoYWVzKHhtaW49Mi41LCB4bWF4PTMuNSwgeW1pbj1sb3dlci0xMDAsIHltYXg9dXBwZXIrMTAwKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBSVHM6XG4gQWRqLiAoTW9kaWZ5aW5nIEFkai4gYW5kIFByZWRpY3RpdmUgQWRqLikgdnMgVmVyYiIsCiAgICAgIHkgPSAiUmVhZGluZyB0aW1lIGRpZmZlcmVuY2UgKG1zKSIsCiAgICAgIHggPSAiU2VudGVuY2UgUmVnaW9uIiwKICAgICAgY29sb3IgPSAiTWVhc3VyZSIKICAgICkgKwogICNjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDkwMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKQoKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUlRfcmVzdWx0c19tYWluX2RpZmZfaW5fbGV4aWNhbC5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9NSwgd2lkdGg9OCkKYGBgCgoKYGBge3J9CiMgUGxvdCB0aGUgcmVhZGluZyB0aW1lcyBpbiBlYWNoIHJlZ2lvbiBicm9rZW4gZG93biBieSBzdGltdWx1cyB0eXBlLCByZWFkaW5nIG1lYXN1cmUgYW5kIHRhcmdldCBnZW5kZXIKCmFnZ19sMiAlPiUKICAjIGZpbHRlcih0eXBlX3MgJWluJSBjKCJzdGltX2FkaiIsICJzdGltX3ZlcmIiLCAic3RpbV9wcmVkX2FkaiIpKSAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoIkZQUmVnIiwgIlJlZ0luX2luY2wiKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiRlBSZWciLCAiUmVnSW5faW5jbCIpLCBsYWJlbHM9YygiRmlyc3QgUGFzcyBSZWdyZXNzaW9uIG91dCBQcm9iLiIsICJSZWdyZXNzaW9uIGluIFByb2IuIikpKSAlPiUKCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbiwgeT1tX2RpZmYsIGNvbG9yID0gbWVhc3VyZSkpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yLjUsIHhtYXg9My41LCB5bWluPS0wLjIsIHltYXg9MC4yKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlmZmVyZW5jZSBpbiBSZWdyZXNzaW9uczogXG5BZGouIChNb2RpZnlpbmcgQWRqLiBhbmQgUHJlZGljdGl2ZSBBZGouKSB2cyBWZXJiIiwKICAgICAgeSA9ICJSZWdyZXNzaW9uIHByb2IuIGRpZmZlcmVuY2UiLAogICAgICB4ID0gIlNlbnRlbmNlIFJlZ2lvbiIsCiAgICAgIGNvbG9yID0gIk1lYXN1cmUiCiAgICApICsKICAjY29vcmRfY2FydGVzaWFuKHlsaW09YygwLCA5MDApKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMTo1KSkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KQogICkKCmdnc2F2ZShwYXN0ZTAoIi4vaW1hZ2VzL1JlZ3Jlc3Npb25fcmVzdWx0c19tYWluX2RpZmZfaW5fbGV4aWNhbC5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9NSwgd2lkdGg9OCkKYGBgCgpgYGB7cn0KYWdnX2wzID0gZGYgJT4lCiAgZ3JvdXBfYnkodHlwZV9sLCBnZW5kZXJfbWF0Y2gsIGl0ZW1faWQsIHJlZ2lvbiwgbWVhc3VyZSkgJT4lCiAgICBzdW1tYXJpc2UoCiAgICAgIG0gPSBtZWFuKHZhbHVlKQogICAgKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkodHlwZV9sLCByZWdpb24sIG1lYXN1cmUpICU+JQogIHBpdm90X3dpZGVyKAogICAgbmFtZXNfZnJvbSA9IGdlbmRlcl9tYXRjaCwKICAgIHZhbHVlc19mcm9tID0gbSwKICAgIG5hbWVzX3ByZWZpeCA9ICJtZWFuXyIKICApICU+JQogICMgQ2FsY3VsYXRlIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gJ01pcycgYW5kICdNYXRjaCcKICBkcm9wX25hKCkgJT4lCiAgbXV0YXRlKAogICAgZGlmZiA9IG1lYW5fTWlzIC0gbWVhbl9NYXRjaAogICkgJT4lCiAgZ3JvdXBfYnkodHlwZV9sLCByZWdpb24sIG1lYXN1cmUpICU+JQogIHN1bW1hcmlzZSgKICAgIG1fZGlmZiA9IG1lYW4oZGlmZiksCiAgICBzID0gc3RkLmVycm9yKGRpZmYpLAogICAgbG93ZXIgPSBtX2RpZmYgLSAxLjk2ICogcywKICAgIHVwcGVyID0gbV9kaWZmICsgMS45NiAqIHMKICApICU+JQogIHVuZ3JvdXAoKQoKIyBWaWV3KGFnZ19sMykKYGBgCgpgYGB7cn0KIyBQbG90IHRoZSByZWFkaW5nIHRpbWVzIGluIGVhY2ggcmVnaW9uIGJyb2tlbiBkb3duIGJ5IHN0aW11bHVzIHR5cGUsIHJlYWRpbmcgbWVhc3VyZSBhbmQgdGFyZ2V0IGdlbmRlcgoKYWdnX2wzICU+JQogICMgZmlsdGVyKHR5cGVfcyAlaW4lIGMoInN0aW1fYWRqIiwgInN0aW1fdmVyYiIsICJzdGltX3ByZWRfYWRqIikpICU+JQogIGZpbHRlcihtZWFzdXJlICVpbiUgYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iKSkgJT4lCiAgCiAgbXV0YXRlKHR5cGVfbCA9IGZhY3Rvcih0eXBlX2wsIGxldmVscyA9IGMoIk1vZGlmeWluZ19BZGpfUHJlZGljdGl2ZV9BZGoiLCAiVmVyYiIpLCBsYWJlbHM9YygiTW9kaWZ5aW5nIEFkai4gJiBQcmVkaWNhdGl2ZSBBZGouIiwgIlZlcmIiKSkpICU+JQogIG11dGF0ZShtZWFzdXJlID0gZmFjdG9yKG1lYXN1cmUsIGxldmVscyA9IGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiksIGxhYmVscz1jKCJHYXplIER1cmF0aW9uIiwgIkdvIFBhc3QgVGltZXMiLCAiVG90YWwgRHVyYXRpb24iKSkpICU+JQoKICBnZ3Bsb3QoYWVzKHg9cmVnaW9uLCB5PW1fZGlmZiwgY29sb3IgPSB0eXBlX2wpKSArCiAgICBnZW9tX3JlY3QoYWVzKHhtaW49Mi41LCB4bWF4PTMuNSwgeW1pbj1sb3dlci0xMDAsIHltYXg9dXBwZXIrMTAwKSwgY29sb3IgPSBOQSwgZmlsbCA9ICJncmVlbiIsIGFscGhhPTAuMDEpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWxvd2VyLCB5bWF4PXVwcGVyKSwgd2lkdGggPSAwLjIpICsKICAgIGdlb21fbGluZSgpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgI2dndGl0bGUocGFzdGUwKCJSZWdpb24gYnkgcmVnaW9uIHBsb3QgZm9yICIsIHN0aW0pKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJSVHMgRGlmZmVyZW5jZSB1bmRlciBNaXNtYXRjaCBhbmQgTWF0Y2ggY29uZGl0aW9ucyIsCiAgICAgIHkgPSAiUmVhZGluZyB0aW1lIGRpZmZlcmVuY2UgKG1zKSIsCiAgICAgIHggPSAiU2VudGVuY2UgUmVnaW9uIiwKICAgICAgY29sb3IgPSAiQWdyZWVtZW50IFR5cGUiCiAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKQoKZ2dzYXZlKHBhc3RlMCgiLi9pbWFnZXMvUlRfcmVzdWx0c19pbnRlcmFjdGlvbl9pbl9sZXhpY2FsLnBkZiIpLCBkZXZpY2U9InBkZiIsIGhlaWdodD01LCB3aWR0aD04KQoKYGBgCgpgYGB7cn0KYWdnX2wzICU+JQogICMgZmlsdGVyKHR5cGVfcyAlaW4lIGMoInN0aW1fYWRqIiwgInN0aW1fdmVyYiIsICJzdGltX3ByZWRfYWRqIikpICU+JQogIGZpbHRlcihtZWFzdXJlICVpbiUgYygiRlBSZWciLCAiUmVnSW5faW5jbCIpKSAlPiUKICAKICBtdXRhdGUodHlwZV9sID0gZmFjdG9yKHR5cGVfbCwgbGV2ZWxzID0gYygiTW9kaWZ5aW5nX0Fkal9QcmVkaWN0aXZlX0FkaiIsICJWZXJiIiksIGxhYmVscz1jKCJNb2RpZnlpbmcgQWRqLiAmIFByZWRpY2F0aXZlIEFkai4iLCAiVmVyYiIpKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiRlBSZWciLCAiUmVnSW5faW5jbCIpLCBsYWJlbHM9YygiRmlyc3QgUGFzcyBSZWdyZXNzaW9uIG91dCBQcm9iLiIsICJSZWdyZXNzaW9uIGluIFByb2IuIikpKSAlPiUKCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbiwgeT1tX2RpZmYsIGNvbG9yID0gdHlwZV9sKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTIuNSwgeG1heD0zLjUsIHltaW49LTAuMywgeW1heD0wLjMpLCBjb2xvciA9IE5BLCBmaWxsID0gImdyZWVuIiwgYWxwaGE9MC4wMSkgKwogICAgZ2VvbV9wb2ludCgpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bG93ZXIsIHltYXg9dXBwZXIpLCB3aWR0aCA9IDAuMikgKwogICAgZ2VvbV9saW5lKCkgKwogICAgZmFjZXRfd3JhcCh+IG1lYXN1cmUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICAjZ2d0aXRsZShwYXN0ZTAoIlJlZ2lvbiBieSByZWdpb24gcGxvdCBmb3IgIiwgc3RpbSkpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIlJlZ3Jlc3Npb24gRGlmZmVyZW5jZSB1bmRlciBNaXNtYXRjaCBhbmQgTWF0Y2ggY29uZGl0aW9ucyIsCiAgICAgIHkgPSAiUmVncmVzc2lvbiBwcm9iLiBkaWZmZXJlbmNlIiwKICAgICAgeCA9ICJTZW50ZW5jZSBSZWdpb24iLAogICAgICBjb2xvciA9ICJBZ3JlZW1lbnQgVHlwZSIKICAgICkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBjKDE6NSkpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkKICApCgpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SZWdyZXNzaW9uX3Jlc3VsdHNfaW50ZXJhY3Rpb25faW5fbGV4aWNhbC5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9NSwgd2lkdGg9OCkKYGBgCgpgYGB7cn0KIyBQbG90IHRoZSByZWFkaW5nIHRpbWVzIGluIGVhY2ggcmVnaW9uIGJyb2tlbiBkb3duIGJ5IHN0aW11bHVzIHR5cGUsIHJlYWRpbmcgbWVhc3VyZSBhbmQgdGFyZ2V0IGdlbmRlcgpWaWV3KGFnZ19zMikKVmlldyhhZ2dfbDIpCgpzMl90ZW1wIDwtIGFnZ19zMiAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiwgIkZQUmVnIiwgIlJlZ0luX2luY2wiKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iLCAiRlBSZWciLCAiUmVnSW5faW5jbCIpLCBsYWJlbHM9YygiR2F6ZSBEdXJhdGlvbiIsICJHbyBQYXN0IFRpbWVzIiwgIlRvdGFsIER1cmF0aW9uIiwgIkZpcnN0IFBhc3MgUmVncmVzc2lvbiBvdXQgUHJvYi4iLCAiUmVncmVzc2lvbiBpbiBQcm9iLiIpKQogICAgICAgICApICU+JQogIG11dGF0ZShQcmVkaWN0aW9uID0gIkZlYXR1cmUtbWF0Y2hpbmciKQpzMl90ZW1wCgpsMl90ZW1wIDwtIGFnZ19sMiAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoImdhemVfZHVyYXRpb24iLCAiZ29fcGFzdF90aW1lIiwgInRvdGFsX2R1cmF0aW9uIiwgIkZQUmVnIiwgIlJlZ0luX2luY2wiKSkgJT4lCiAgbXV0YXRlKG1lYXN1cmUgPSBmYWN0b3IobWVhc3VyZSwgbGV2ZWxzID0gYygiZ2F6ZV9kdXJhdGlvbiIsICJnb19wYXN0X3RpbWUiLCAidG90YWxfZHVyYXRpb24iLCAiRlBSZWciLCAiUmVnSW5faW5jbCIpLCBsYWJlbHM9YygiR2F6ZSBEdXJhdGlvbiIsICJHbyBQYXN0IFRpbWVzIiwgIlRvdGFsIER1cmF0aW9uIiwgIkZpcnN0IFBhc3MgUmVncmVzc2lvbiBvdXQgUHJvYi4iLCAiUmVncmVzc2lvbiBpbiBQcm9iLiIpKQogICAgICAgICApICU+JQogIG11dGF0ZShQcmVkaWN0aW9uID0gIkxleGljYWwiKQpsMl90ZW1wCgphZ2dfc2wyIDwtIHJiaW5kKHMyX3RlbXAsIGwyX3RlbXApICU+JQogIG11dGF0ZShQcmVkaWN0aW9uID0gZmFjdG9yKFByZWRpY3Rpb24sIGxldmVscyA9IGMoIkZlYXR1cmUtbWF0Y2hpbmciLCAiTGV4aWNhbCIpLCBsYWJlbHM9YygiRmVhdHVyZS1tYXRjaGluZyBNZWNoYW5pc20iLCAiTGV4aWNhbCBDYXRlZ29yeSIpKSkgClZpZXcoYWdnX3NsMikKCmFnZ19zbDIgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJHYXplIER1cmF0aW9uIiwgIkdvIFBhc3QgVGltZXMiLCAiVG90YWwgRHVyYXRpb24iKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVnaW9uLCB5ID0gbV9kaWZmLCBjb2xvciA9IG1lYXN1cmUsIGdyb3VwID0gUHJlZGljdGlvbiwgbGluZXR5cGUgPSBQcmVkaWN0aW9uKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluID0gMi41LCB4bWF4ID0gMy41LCB5bWluID0gbG93ZXIgLSAxMDAsIHltYXggPSB1cHBlciArIDEwMCksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYSA9IDAuMDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyYXkzMCIpICsgCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IFByZWRpY3Rpb24pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4zKSkgKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGxvd2VyLCB5bWF4ID0gdXBwZXIpLCB3aWR0aCA9IDAuMiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICAgIGdlb21fbGluZSggcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRmVhdHVyZS1tYXRjaGluZyBNZWNoYW5pc20gdnMgTGV4aWNhbCBjYXRlZ29yeTpcbiBSVChBZ3JlZW1lbnQgLSBDb25jb3JkKSAgdnMgUlQoQWRqIC0gVmVyYikiLAogICAgICB5ID0gIlJlYWRpbmcgdGltZSBkaWZmZXJlbmNlIChtcykiLAogICAgICB4ID0gIlNlbnRlbmNlIFJlZ2lvbiIsCiAgICAgIGxpbmV0eXBlID0gIlByZWRpY3Rpb24iCiAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoInNvbGlkIiwgImRhc2hlZCIpKSArCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UsIHNoYXBlID0gRkFMU0UpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkKICApCgpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SVF9tYWluX2RpZmZfYm90aF90aG9lcnkucGRmIiksIGRldmljZT0icGRmIiwgaGVpZ2h0PTQsIHdpZHRoPTgpCmBgYAoKYGBge3J9CiMgUGxvdCB0aGUgcmVhZGluZyB0aW1lcyBpbiBlYWNoIHJlZ2lvbiBicm9rZW4gZG93biBieSBzdGltdWx1cyB0eXBlLCByZWFkaW5nIG1lYXN1cmUgYW5kIHRhcmdldCBnZW5kZXIKCmFnZ19zbDIgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJGaXJzdCBQYXNzIFJlZ3Jlc3Npb24gb3V0IFByb2IuIiwgIlJlZ3Jlc3Npb24gaW4gUHJvYi4iKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXJlZ2lvbiwgeT1tX2RpZmYsIGNvbG9yID0gbWVhc3VyZSwgZ3JvdXAgPSBQcmVkaWN0aW9uLCBsaW5ldHlwZSA9IFByZWRpY3Rpb24pKSArCiAgICBnZW9tX3JlY3QoYWVzKHhtaW49Mi41LCB4bWF4PTMuNSwgeW1pbj0tMC4yLCB5bWF4PTAuMiksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYT0wLjAxKSArCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBjb2xvciA9ICJncmF5MzAiKSArIAogICAgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSBQcmVkaWN0aW9uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSwgd2lkdGggPSAwLjIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjMpKSArCiAgICBnZW9tX2xpbmUocG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMykpICsKICAgIGZhY2V0X3dyYXAofiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgID0gIkZlYXR1cmUtbWF0Y2hpbmcgTWVjaGFuaXNtIHZzIExleGljYWwgY2F0ZWdvcnk6XG5SZWdfUHJvYi4oQWdyZWVtZW50IC0gQ29uY29yZCkgdnMgUmVnX1Byb2IuKEFkaiAtIFZlcmIpIiwKICAgICAgeSA9ICJSZWdyZXNzaW9uIGRpZmZlcmVuY2UgKG1zKSIsCiAgICAgIHggPSAiU2VudGVuY2UgUmVnaW9uIiwKICAgICAgbGluZXR5cGUgPSAiUHJlZGljdGlvbiIKICAgICkgKwogICNjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsIDkwMCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgc2NhbGVfbGluZXR5cGVfbWFudWFsKHZhbHVlcyA9IGMoInNvbGlkIiwgImRhc2hlZCIpKSArCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UsIHNoYXBlID0gRkFMU0UpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkKICApCgpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SZWdyZXNzaW9uX21haW5fZGlmZl9ib3RoX3Rob2VyeS5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9NCwgd2lkdGg9MTYvMykKYGBgCgpgYGB7cn0KczNfdGVtcCA8LSBhZ2dfczMgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIsICJGUFJlZyIsICJSZWdJbl9pbmNsIikpICU+JQogIG11dGF0ZSh0eXBlX3MgPSBmYWN0b3IodHlwZV9zLCBsZXZlbHMgPSBjKCJNb2RpZnlpbmdfQWRqIiwgIlByZWRpY3RpdmVfQWRqX1ZlcmIiKSwgbGFiZWxzPWMoIkNvbmNvcmQiLCAiQWdyZWVtZW50IikpKSAlPiUKICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIsICJGUFJlZyIsICJSZWdJbl9pbmNsIiksIGxhYmVscz1jKCJHYXplIER1cmF0aW9uIiwgIkdvIFBhc3QgVGltZXMiLCAiVG90YWwgRHVyYXRpb24iLCAiRmlyc3QgUGFzcyBSZWdyZXNzaW9uIG91dCBQcm9iLiIsICJSZWdyZXNzaW9uIGluIFByb2IuIikpCiAgICAgICAgICkgJT4lCiAgbXV0YXRlKFByZWRpY3Rpb24gPSAiRmVhdHVyZS1tYXRjaGluZyIpICU+JSAKICByZW5hbWUodHlwZSA9IHR5cGVfcykKczNfdGVtcAoKbDNfdGVtcCA8LSBhZ2dfbDMgJT4lCiAgZmlsdGVyKG1lYXN1cmUgJWluJSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIsICJGUFJlZyIsICJSZWdJbl9pbmNsIikpICU+JQogIG11dGF0ZSh0eXBlX2wgPSBmYWN0b3IodHlwZV9sLCBsZXZlbHMgPSBjKCJNb2RpZnlpbmdfQWRqX1ByZWRpY3RpdmVfQWRqIiwgIlZlcmIiKSwgbGFiZWxzPWMoIkFkamVjdGl2ZSIsICJWZXJiIikpKSAlPiUKICBtdXRhdGUobWVhc3VyZSA9IGZhY3RvcihtZWFzdXJlLCBsZXZlbHMgPSBjKCJnYXplX2R1cmF0aW9uIiwgImdvX3Bhc3RfdGltZSIsICJ0b3RhbF9kdXJhdGlvbiIsICJGUFJlZyIsICJSZWdJbl9pbmNsIiksIGxhYmVscz1jKCJHYXplIER1cmF0aW9uIiwgIkdvIFBhc3QgVGltZXMiLCAiVG90YWwgRHVyYXRpb24iLCAiRmlyc3QgUGFzcyBSZWdyZXNzaW9uIG91dCBQcm9iLiIsICJSZWdyZXNzaW9uIGluIFByb2IuIikpCiAgICAgICAgICkgJT4lCiAgbXV0YXRlKFByZWRpY3Rpb24gPSAiTGV4aWNhbCIpICU+JQogIHJlbmFtZSh0eXBlID0gdHlwZV9sKQpsM190ZW1wCgphZ2dfc2wzIDwtIGFnZ19zbDMgJT4lCiAgbXV0YXRlKAogICAgU2lnID0gY2FzZV93aGVuKAogICAgICByZWdpb24gPT0gMyAmIG1lYXN1cmUgPT0gIkdvIFBhc3QgVGltZXMiICYgdHlwZSA9PSAiQ29uY29yZCIgfiAwLjAzLAogICAgICByZWdpb24gPT0gMyAmIG1lYXN1cmUgPT0gIlRvdGFsIER1cmF0aW9uIiAmIHR5cGUgPT0gIkNvbmNvcmQiIH4gMC4wOCwKICAgICAgVFJVRSB+IDEKICAgICksCiAgICBhbm5vdGF0aW9uID0gY2FzZV93aGVuKAogICAgICBTaWcgPCAwLjA1IH4gIioiLAogICAgICBTaWcgPj0gMC4wNSAmIFNpZyA8IDAuMSB+ICLCtyIsCiAgICAgIFRSVUUgfiAiIgogICAgKSwKICAgIGFubm90YXRpb25feSA9IDI4MCAgCiAgKQpWaWV3KGFnZ19zbDMpCgpgYGAKCgpgYGB7cn0KYWdnX3NsMyAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoIkdhemUgRHVyYXRpb24iLCAiR28gUGFzdCBUaW1lcyIsICJUb3RhbCBEdXJhdGlvbiIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZWdpb24sIHkgPSBtX2RpZmYsIGNvbG9yID0gdHlwZSwgZ3JvdXAgPSBpbnRlcmFjdGlvbihQcmVkaWN0aW9uLCB0eXBlKSwgbGluZXR5cGUgPSBQcmVkaWN0aW9uKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluID0gMi41LCB4bWF4ID0gMy41LCB5bWluID0gbG93ZXIgLSAxMDAsIHltYXggPSB1cHBlciArIDEwMCksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYSA9IDAuMDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyYXkzMCIpICsgCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHR5cGUpKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciksIHdpZHRoID0gMC4yKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gYW5ub3RhdGlvbiwgeSA9IGFubm90YXRpb25feSksIHZqdXN0ID0gMCwgY29sb3IgPSAiYmxhY2siKSArCiAgICBmYWNldF9ncmlkKFByZWRpY3Rpb24gfiBtZWFzdXJlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiSW50ZXJhY3Rpb24gYmV0d2VlbiBHcmFtbWF0aWNhbGl0eSBhbmQgXG4gRmVhdHVyZS1tYXRjaCBNZWNoYW5pc20gLyBMZXhpY2FsIENhdGVnb3J5IiwKICAgICAgeSA9ICJSZWFkaW5nIHRpbWUgZGlmZmVyZW5jZSAoTWlzIC0gTWF0Y2gpIiwKICAgICAgeCA9ICJTZW50ZW5jZSBSZWdpb24iCiAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoCiAgICAiQ29uY29yZCIgPSAiIzU2QkNDMiIsCiAgICAiQWdyZWVtZW50IiA9ICIjRTc3RDcyIiwKICAgICJBZGplY3RpdmUiID0gIiM1NkJDQzIiLAogICAgIlZlcmIiID0gIiNFNzdENzIiCiAgKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKAogICAgIkNvbmNvcmQiID0gMTYsICMgRmlsbGVkIGNpcmNsZQogICAgIkFncmVlbWVudCIgPSAxNywgIyBGaWxsZWQgdHJpYW5nbGUKICAgICJBZGplY3RpdmUiID0gMTYsICMgRmlsbGVkIGNpcmNsZQogICAgIlZlcmIiID0gMTcgIyBGaWxsZWQgdHJpYW5nbGUKICApKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKSArCiAgZ3VpZGVzKAogICAgbGluZXR5cGUgPSAibm9uZSIsCiAgICBjb2xvciA9IGd1aWRlX2xlZ2VuZCgKICAgICAgdGl0bGUgPSAiVHlwZSIsCiAgICAgIG5jb2wgPSA0LAogICAgICBieXJvdyA9IFRSVUUsCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgbGluZXR5cGUgPSBjKCJzb2xpZCIsICJzb2xpZCIsICJkb3RkYXNoIiwgImRvdGRhc2giKSwKICAgICAgICBzaGFwZSA9IGMoMTYsIDE3LCAxNiwgMTcpCiAgICAgICkKICAgICksCiAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZCgKICAgICAgdGl0bGUgPSAiVHlwZSIsCiAgICAgIG5jb2wgPSA0LAogICAgICBieXJvdyA9IFRSVUUsCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgbGluZXR5cGUgPSBjKCJzb2xpZCIsICJzb2xpZCIsICJkb3RkYXNoIiwgImRvdGRhc2giKQogICAgICApCiAgICApCiAgKQpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SVF9pbnRlcmFjdGlvbl9ib3RoX3Rob2VyeS5wZGYiKSwgZGV2aWNlPSJwZGYiLCBoZWlnaHQ9NSwgd2lkdGg9OCkKYGBgCgpgYGB7cn0KYWdnX3NsMyAlPiUKICBmaWx0ZXIobWVhc3VyZSAlaW4lIGMoIkZpcnN0IFBhc3MgUmVncmVzc2lvbiBvdXQgUHJvYi4iLCAiUmVncmVzc2lvbiBpbiBQcm9iLiIpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZWdpb24sIHkgPSBtX2RpZmYsIGNvbG9yID0gdHlwZSwgZ3JvdXAgPSBpbnRlcmFjdGlvbihQcmVkaWN0aW9uLCB0eXBlKSwgbGluZXR5cGUgPSBQcmVkaWN0aW9uKSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluID0gMi41LCB4bWF4ID0gMy41LCB5bWluID0gbG93ZXIgLSAwLjIsIHltYXggPSB1cHBlciArIDAuMiksIGNvbG9yID0gTkEsIGZpbGwgPSAiZ3JlZW4iLCBhbHBoYSA9IDAuMDEpICsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gImdyYXkzMCIpICsgCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHR5cGUpKSArCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciksIHdpZHRoID0gMC4yKSArCiAgICBnZW9tX2xpbmUoKSArCiAgICAjIGdlb21fdGV4dChhZXMobGFiZWwgPSBhbm5vdGF0aW9uLCB5ID0gYW5ub3RhdGlvbl95KSwgdmp1c3QgPSAwLCBjb2xvciA9ICJibGFjayIpICsKICAgIGZhY2V0X2dyaWQoUHJlZGljdGlvbiB+IG1lYXN1cmUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgICBsYWJzKAogICAgICB0aXRsZSA9ICJJbnRlcmFjdGlvbiBiZXR3ZWVuIEdyYW1tYXRpY2FsaXR5IGFuZCBcbiBGZWF0dXJlLW1hdGNoIE1lY2hhbmlzbSAvIExleGljYWwgQ2F0ZWdvcnkiLAogICAgICB5ID0gIlJlZ3Jlc3Npb24gcHJvYi4gZGlmZmVyZW5jZSAoTWlzIC0gTWF0Y2gpIiwKICAgICAgeCA9ICJTZW50ZW5jZSBSZWdpb24iCiAgICApICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjUpKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoCiAgICAiQ29uY29yZCIgPSAiIzU2QkNDMiIsCiAgICAiQWdyZWVtZW50IiA9ICIjRTc3RDcyIiwKICAgICJBZGplY3RpdmUiID0gIiM1NkJDQzIiLAogICAgIlZlcmIiID0gIiNFNzdENzIiCiAgKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKAogICAgIkNvbmNvcmQiID0gMTYsICMgRmlsbGVkIGNpcmNsZQogICAgIkFncmVlbWVudCIgPSAxNywgIyBGaWxsZWQgdHJpYW5nbGUKICAgICJBZGplY3RpdmUiID0gMTYsICMgRmlsbGVkIGNpcmNsZQogICAgIlZlcmIiID0gMTcgIyBGaWxsZWQgdHJpYW5nbGUKICApKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpCiAgKSArCiAgZ3VpZGVzKAogICAgbGluZXR5cGUgPSAibm9uZSIsCiAgICBjb2xvciA9IGd1aWRlX2xlZ2VuZCgKICAgICAgdGl0bGUgPSAiVHlwZSIsCiAgICAgIG5jb2wgPSA0LAogICAgICBieXJvdyA9IFRSVUUsCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgbGluZXR5cGUgPSBjKCJzb2xpZCIsICJzb2xpZCIsICJkb3RkYXNoIiwgImRvdGRhc2giKSwKICAgICAgICBzaGFwZSA9IGMoMTYsIDE3LCAxNiwgMTcpCiAgICAgICkKICAgICksCiAgICBzaGFwZSA9IGd1aWRlX2xlZ2VuZCgKICAgICAgdGl0bGUgPSAiVHlwZSIsCiAgICAgIG5jb2wgPSA0LAogICAgICBieXJvdyA9IFRSVUUsCiAgICAgIG92ZXJyaWRlLmFlcyA9IGxpc3QoCiAgICAgICAgbGluZXR5cGUgPSBjKCJzb2xpZCIsICJzb2xpZCIsICJkb3RkYXNoIiwgImRvdGRhc2giKQogICAgICApCiAgICApCiAgKQpnZ3NhdmUocGFzdGUwKCIuL2ltYWdlcy9SZWdyZXNzaW9uX2ludGVyYWN0aW9uX2JvdGhfdGhvZXJ5LnBkZiIpLCBkZXZpY2U9InBkZiIsIGhlaWdodD01LCB3aWR0aD0xNi8zKQpgYGAKCg==